summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.cpp102
-rw-r--r--src/ast/ast.hpp113
-rw-r--r--src/ast/attrs.hpp12
-rw-r--r--src/ast/crate.cpp146
-rw-r--r--src/ast/crate.hpp20
-rw-r--r--src/ast/dump.cpp49
-rw-r--r--src/ast/expr.cpp12
-rw-r--r--src/ast/expr.hpp39
-rw-r--r--src/ast/expr_ptr.hpp1
-rw-r--r--src/ast/generics.hpp6
-rw-r--r--src/ast/item.hpp15
-rw-r--r--src/ast/macro.hpp10
-rw-r--r--src/ast/path.cpp164
-rw-r--r--src/ast/path.hpp168
-rw-r--r--src/ast/pattern.cpp2
-rw-r--r--src/ast/pattern.hpp4
-rw-r--r--src/ast/types.cpp9
-rw-r--r--src/ast/types.hpp13
-rw-r--r--src/common.hpp21
-rw-r--r--src/coretypes.hpp2
-rw-r--r--src/debug.cpp8
-rw-r--r--src/expand/asm.cpp6
-rw-r--r--src/expand/assert.cpp88
-rw-r--r--src/expand/cfg.cpp14
-rw-r--r--src/expand/concat.cpp4
-rw-r--r--src/expand/crate_tags.cpp22
-rw-r--r--src/expand/derive.cpp776
-rw-r--r--src/expand/env.cpp20
-rw-r--r--src/expand/file_line.cpp26
-rw-r--r--src/expand/format_args.cpp203
-rw-r--r--src/expand/include.cpp19
-rw-r--r--src/expand/lang_item.cpp94
-rw-r--r--src/expand/macro_rules.cpp28
-rw-r--r--src/expand/mod.cpp287
-rw-r--r--src/expand/proc_macro.cpp91
-rw-r--r--src/expand/proc_macro.hpp8
-rw-r--r--src/expand/rustc_diagnostics.cpp14
-rw-r--r--src/expand/std_prelude.cpp8
-rw-r--r--src/expand/stringify.cpp6
-rw-r--r--src/expand/test.cpp15
-rw-r--r--src/expand/test_harness.cpp19
-rw-r--r--src/hir/crate_post_load.cpp2
-rw-r--r--src/hir/deserialise.cpp376
-rw-r--r--src/hir/dump.cpp79
-rw-r--r--src/hir/expr.cpp9
-rw-r--r--src/hir/expr.hpp38
-rw-r--r--src/hir/expr_ptr.cpp16
-rw-r--r--src/hir/expr_ptr.hpp1
-rw-r--r--src/hir/expr_state.hpp6
-rw-r--r--src/hir/from_ast.cpp503
-rw-r--r--src/hir/from_ast.hpp2
-rw-r--r--src/hir/from_ast_expr.cpp72
-rw-r--r--src/hir/generic_params.cpp2
-rw-r--r--src/hir/generic_params.hpp16
-rw-r--r--src/hir/hir.cpp1107
-rw-r--r--src/hir/hir.hpp205
-rw-r--r--src/hir/hir_ops.cpp1148
-rw-r--r--src/hir/item_path.hpp20
-rw-r--r--src/hir/main_bindings.hpp2
-rw-r--r--src/hir/path.cpp6
-rw-r--r--src/hir/path.hpp26
-rw-r--r--src/hir/pattern.cpp72
-rw-r--r--src/hir/pattern.hpp21
-rw-r--r--src/hir/serialise.cpp202
-rw-r--r--src/hir/serialise_lowlevel.cpp62
-rw-r--r--src/hir/serialise_lowlevel.hpp31
-rw-r--r--src/hir/type.cpp121
-rw-r--r--src/hir/type.hpp52
-rw-r--r--src/hir/visitor.cpp54
-rw-r--r--src/hir/visitor.hpp3
-rw-r--r--src/hir_conv/bind.cpp230
-rw-r--r--src/hir_conv/constant_evaluation.cpp505
-rw-r--r--src/hir_conv/constant_evaluation.hpp33
-rw-r--r--src/hir_conv/expand_type.cpp19
-rw-r--r--src/hir_conv/main_bindings.hpp6
-rw-r--r--src/hir_conv/markings.cpp15
-rw-r--r--src/hir_conv/resolve_ufcs.cpp35
-rw-r--r--src/hir_conv/resolve_ufcs_outer.cpp384
-rw-r--r--src/hir_expand/annotate_value_usage.cpp59
-rw-r--r--src/hir_expand/closures.cpp397
-rw-r--r--src/hir_expand/reborrow.cpp4
-rw-r--r--src/hir_expand/ufcs_everything.cpp8
-rw-r--r--src/hir_expand/vtable.cpp30
-rw-r--r--src/hir_typeck/common.cpp25
-rw-r--r--src/hir_typeck/common.hpp22
-rw-r--r--src/hir_typeck/expr_check.cpp220
-rw-r--r--src/hir_typeck/expr_cs.cpp4034
-rw-r--r--src/hir_typeck/expr_visit.cpp92
-rw-r--r--src/hir_typeck/expr_visit.hpp20
-rw-r--r--src/hir_typeck/helpers.cpp1001
-rw-r--r--src/hir_typeck/helpers.hpp27
-rw-r--r--src/hir_typeck/impl_ref.cpp61
-rw-r--r--src/hir_typeck/impl_ref.hpp17
-rw-r--r--src/hir_typeck/outer.cpp121
-rw-r--r--src/hir_typeck/static.cpp567
-rw-r--r--src/hir_typeck/static.hpp60
-rw-r--r--src/ident.cpp5
-rw-r--r--src/include/debug.hpp13
-rw-r--r--src/include/ident.hpp28
-rw-r--r--src/include/main_bindings.hpp1
-rw-r--r--src/include/rc_string.hpp116
-rw-r--r--src/include/span.hpp1
-rw-r--r--src/include/synext_decorator.hpp3
-rw-r--r--src/include/synext_macro.hpp6
-rw-r--r--src/include/tagged_union.hpp12
-rw-r--r--src/include/target_version.hpp19
-rw-r--r--src/macro_rules/eval.cpp892
-rw-r--r--src/macro_rules/macro_rules.hpp54
-rw-r--r--src/macro_rules/mod.cpp51
-rw-r--r--src/macro_rules/parse.cpp509
-rw-r--r--src/macro_rules/pattern_checks.hpp1
-rw-r--r--src/main.cpp144
-rw-r--r--src/mir/check.cpp198
-rw-r--r--src/mir/check_full.cpp230
-rw-r--r--src/mir/cleanup.cpp176
-rw-r--r--src/mir/dump.cpp45
-rw-r--r--src/mir/from_hir.cpp400
-rw-r--r--src/mir/from_hir.hpp22
-rw-r--r--src/mir/from_hir_match.cpp354
-rw-r--r--src/mir/helpers.cpp145
-rw-r--r--src/mir/helpers.hpp11
-rw-r--r--src/mir/mir.cpp208
-rw-r--r--src/mir/mir.hpp452
-rw-r--r--src/mir/mir_builder.cpp636
-rw-r--r--src/mir/mir_ptr.hpp9
-rw-r--r--src/mir/optimise.cpp1686
-rw-r--r--src/parse/common.hpp5
-rw-r--r--src/parse/eTokenType.enum.h3
-rw-r--r--src/parse/expr.cpp91
-rw-r--r--src/parse/interpolated_fragment.cpp11
-rw-r--r--src/parse/interpolated_fragment.hpp3
-rw-r--r--src/parse/lex.cpp23
-rw-r--r--src/parse/parseerror.cpp22
-rw-r--r--src/parse/paths.cpp42
-rw-r--r--src/parse/pattern.cpp75
-rw-r--r--src/parse/root.cpp920
-rw-r--r--src/parse/token.cpp56
-rw-r--r--src/parse/token.hpp7
-rw-r--r--src/parse/tokenstream.cpp4
-rw-r--r--src/parse/tokenstream.hpp2
-rw-r--r--src/parse/types.cpp83
-rw-r--r--src/rc_string.cpp113
-rw-r--r--src/resolve/absolute.cpp425
-rw-r--r--src/resolve/index.cpp333
-rw-r--r--src/resolve/use.cpp686
-rw-r--r--src/slice.hpp35
-rw-r--r--src/span.cpp6
-rw-r--r--src/trans/allocator.cpp19
-rw-r--r--src/trans/allocator.hpp10
-rw-r--r--src/trans/auto_impls.cpp248
-rw-r--r--src/trans/codegen.cpp15
-rw-r--r--src/trans/codegen.hpp2
-rw-r--r--src/trans/codegen_c.cpp1055
-rw-r--r--src/trans/codegen_mmir.cpp422
-rw-r--r--src/trans/enumerate.cpp953
-rw-r--r--src/trans/main_bindings.hpp4
-rw-r--r--src/trans/mangling.cpp17
-rw-r--r--src/trans/mangling_v2.cpp292
-rw-r--r--src/trans/monomorphise.cpp80
-rw-r--r--src/trans/target.cpp192
-rw-r--r--src/trans/target.hpp13
-rw-r--r--src/trans/trans_list.cpp17
-rw-r--r--src/trans/trans_list.hpp17
-rw-r--r--src/version.cpp8
164 files changed, 18558 insertions, 9088 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index e4fe49da..827ac2d1 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -107,18 +107,15 @@ Function Function::clone() const
return rv;
}
-void Trait::add_type(::std::string name, AttributeList attrs, TypeRef type) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) );
- m_items.back().data.attrs = mv$(attrs);
+void Trait::add_type(Span sp, RcString name, AttributeList attrs, TypeRef type) {
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))})) );
}
-void Trait::add_function(::std::string name, AttributeList attrs, Function fcn) {
+void Trait::add_function(Span sp, RcString name, AttributeList attrs, Function fcn) {
DEBUG("trait fn " << name);
- m_items.push_back( Named<Item>(mv$(name), Item::make_Function({mv$(fcn)}), true) );
- m_items.back().data.attrs = mv$(attrs);
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Function({mv$(fcn)})) );
}
-void Trait::add_static(::std::string name, AttributeList attrs, Static v) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Static({mv$(v)}), true) );
- m_items.back().data.attrs = mv$(attrs);
+void Trait::add_static(Span sp, RcString name, AttributeList attrs, Static v) {
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Static({mv$(v)})) );
}
void Trait::set_is_marker() {
m_is_marker = true;
@@ -126,7 +123,7 @@ void Trait::set_is_marker() {
bool Trait::is_marker() const {
return m_is_marker;
}
-bool Trait::has_named_item(const ::std::string& name, bool& out_is_fcn) const
+bool Trait::has_named_item(const RcString& name, bool& out_is_fcn) const
{
for( const auto& i : m_items )
{
@@ -143,7 +140,7 @@ Trait Trait::clone() const
auto rv = Trait(m_params.clone(), m_supertraits);
for(const auto& item : m_items)
{
- rv.m_items.push_back( Named<Item> { item.name, item.data.clone(), item.is_pub } );
+ rv.m_items.push_back( Named<Item> { item.span, item.attrs.clone(), item.is_pub, item.name, item.data.clone() } );
}
return rv;
}
@@ -208,24 +205,24 @@ Union Union::clone() const
return os << "impl<" << impl.m_params << "> " << impl.m_trait.ent << " for " << impl.m_type << "";
}
-void Impl::add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn)
+void Impl::add_function(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Function fcn)
{
DEBUG("impl fn " << name);
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Function(mv$(fcn)) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Function(mv$(fcn)) ) } );
}
-void Impl::add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type)
+void Impl::add_type(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, TypeRef type)
{
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Type(TypeAlias(GenericParams(), mv$(type))) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Type(TypeAlias(GenericParams(), mv$(type))) ) } );
}
-void Impl::add_static(bool is_public, bool is_specialisable, ::std::string name, Static v)
+void Impl::add_static(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Static v)
{
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } );
}
void Impl::add_macro_invocation(MacroInvocation item) {
- m_items.push_back( ImplItem { false, false, "", box$( Item::make_MacroInv(mv$(item)) ) } );
+ m_items.push_back( ImplItem { item.span(), {}, false, false, "", box$( Item::make_MacroInv(mv$(item)) ) } );
}
-bool Impl::has_named_item(const ::std::string& name) const
+bool Impl::has_named_item(const RcString& name) const
{
for( const auto& it : this->items() )
{
@@ -241,28 +238,28 @@ bool Impl::has_named_item(const ::std::string& name) const
return os << impl.m_def;
}
-::std::ostream& operator<<(::std::ostream& os, const UseStmt& x)
-{
- os << "Use(" << x.path << ")";
- return os;
-}
-
-
MacroInvocation MacroInvocation::clone() const
{
return MacroInvocation(m_span, m_macro_name, m_ident, m_input.clone());
}
-
-UseStmt UseStmt::clone() const
+UseItem UseItem::clone() const
{
- return UseStmt(sp, path);
+ decltype(this->entries) entries;
+ for(const auto& e : this->entries)
+ {
+ entries.push_back({ e.sp, e.path, e.name });
+ }
+ return UseItem {
+ this->sp,
+ mv$(entries)
+ };
}
void ExternBlock::add_item(Named<Item> named_item)
{
- ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static(), "Incorrect item type for ExternBlock");
+ ASSERT_BUG(named_item.span, named_item.data.is_Function() || named_item.data.is_Static() || named_item.data.is_Type(), "Incorrect item type for ExternBlock - " << named_item.data.tag_str());
m_items.push_back( mv$(named_item) );
}
ExternBlock ExternBlock::clone() const
@@ -271,7 +268,7 @@ ExternBlock ExternBlock::clone() const
}
::std::shared_ptr<AST::Module> Module::add_anon() {
- auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + FMT("#" << m_anon_modules.size())) );
+ auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + RcString::new_interned(FMT("#" << m_anon_modules.size()))) );
DEBUG("New anon " << rv->m_my_path);
rv->m_file_info = m_file_info;
@@ -286,55 +283,54 @@ void Module::add_item( Named<Item> named_item ) {
if( i.name == "" ) {
}
else {
- DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.data.attrs);
+ DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.attrs);
}
}
-void Module::add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs) {
- it.attrs = mv$(attrs);
- add_item( Named<Item>( mv$(name), mv$(it), is_pub ) );
-}
-void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs) {
- this->add_item( is_public, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) );
+void Module::add_item(Span sp, bool is_pub, RcString name, Item it, AttributeList attrs) {
+ add_item( Named<Item>( mv$(sp), mv$(attrs), is_pub, mv$(name), mv$(it) ) );
}
-void Module::add_alias(bool is_public, UseStmt us, ::std::string name, AttributeList attrs) {
- this->add_item( is_public, mv$(name), Item(mv$(us)), mv$(attrs) );
+void Module::add_ext_crate(Span sp, bool is_pub, RcString ext_name, RcString imp_name, AttributeList attrs) {
+ this->add_item( mv$(sp), is_pub, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) );
}
void Module::add_macro_invocation(MacroInvocation item) {
- this->add_item( false, "", Item( mv$(item) ), ::AST::AttributeList {} );
+ this->add_item( item.span(), false, "", Item( mv$(item) ), ::AST::AttributeList {} );
}
-void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) {
- m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) );
+void Module::add_macro(bool is_exported, RcString name, MacroRulesPtr macro) {
+ m_macros.push_back( Named<MacroRulesPtr>( Span(), {}, /*is_pub=*/is_exported, mv$(name), mv$(macro) ) );
}
-void Module::add_macro_import(::std::string name, const MacroRules& mr) {
- m_macro_import_res.push_back( Named<const MacroRules*>( mv$(name), &mr, false ) );
+void Module::add_macro_import(RcString name, const MacroRules& mr) {
+ m_macro_import_res.push_back( Named<const MacroRules*>( Span(), /*attrs=*/{}, /*is_pub=*/false, mv$(name), &mr) );
}
Item Item::clone() const
{
TU_MATCHA( (*this), (e),
(None,
- return AST::Item(e);
+ return Item(e);
),
(MacroInv,
- TODO(this->span, "Clone on Item::MacroInv");
+ TODO(Span(), "Clone on Item::MacroInv");
+ ),
+ (Macro,
+ TODO(Span(), "Clone on Item::Macro");
),
(Use,
- return AST::Item(e.clone());
+ return Item(e.clone());
),
(ExternBlock,
- TODO(this->span, "Clone on Item::" << this->tag_str());
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Impl,
- TODO(this->span, "Clone on Item::Impl");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(NegImpl,
- TODO(this->span, "Clone on Item::NegImpl");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Module,
- TODO(this->span, "Clone on Item::Module");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Crate,
- return AST::Item(e);
+ return Item(e);
),
(Type,
return AST::Item(e.clone());
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 0a43cc71..1f42a764 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>
@@ -40,11 +42,16 @@ class Item;
using ::std::unique_ptr;
using ::std::move;
+typedef bool Visibility;
+
enum eItemType
{
ITEM_TRAIT,
ITEM_STRUCT,
+ ITEM_ENUM,
+ ITEM_UNION,
ITEM_FN,
+ ITEM_EXTERN_FN,
ITEM_STATIC,
};
@@ -52,12 +59,12 @@ struct StructItem
{
::AST::AttributeList m_attrs;
bool m_is_public;
- ::std::string m_name;
+ RcString m_name;
TypeRef m_type;
//StructItem() {}
- StructItem(::AST::AttributeList attrs, bool is_pub, ::std::string name, TypeRef ty):
+ StructItem(::AST::AttributeList attrs, bool is_pub, RcString name, TypeRef ty):
m_attrs( mv$(attrs) ),
m_is_public(is_pub),
m_name( mv$(name) ),
@@ -216,16 +223,16 @@ public:
const NamedList<Item>& items() const { return m_items; }
NamedList<Item>& items() { return m_items; }
- void add_type(::std::string name, AttributeList attrs, TypeRef type);
- void add_function(::std::string name, AttributeList attrs, Function fcn);
- void add_static(::std::string name, AttributeList attrs, Static v);
+ void add_type(Span sp, RcString name, AttributeList attrs, TypeRef type);
+ void add_function(Span sp, RcString name, AttributeList attrs, Function fcn);
+ void add_static(Span sp, RcString name, AttributeList attrs, Static v);
void set_is_marker();
bool is_marker() const;
void set_is_unsafe() { m_is_unsafe = true; }
bool is_unsafe() const { return m_is_unsafe; }
- bool has_named_item(const ::std::string& name, bool& out_is_fcn) const;
+ bool has_named_item(const RcString& name, bool& out_is_fcn) const;
Trait clone() const;
};
@@ -251,28 +258,28 @@ TAGGED_UNION_EX(EnumVariantData, (), Value,
struct EnumVariant
{
AttributeList m_attrs;
- ::std::string m_name;
+ RcString m_name;
EnumVariantData m_data;
EnumVariant()
{
}
- EnumVariant(AttributeList attrs, ::std::string name, Expr&& value):
+ EnumVariant(AttributeList attrs, RcString name, Expr&& value):
m_attrs( mv$(attrs) ),
m_name( mv$(name) ),
m_data( EnumVariantData::make_Value({mv$(value)}) )
{
}
- EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<TypeRef> sub_types):
+ EnumVariant(AttributeList attrs, RcString name, ::std::vector<TypeRef> sub_types):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) )
{
}
- EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<StructItem> fields):
+ EnumVariant(AttributeList attrs, RcString name, ::std::vector<StructItem> fields):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Struct( {mv$(fields)} ) )
@@ -417,9 +424,11 @@ class Impl
{
public:
struct ImplItem {
+ Span sp;
+ AttributeList attrs;
bool is_pub; // Ignored for trait impls
bool is_specialisable;
- ::std::string name;
+ RcString name;
::std::unique_ptr<Item> data;
};
@@ -439,9 +448,9 @@ public:
{}
Impl& operator=(Impl&&) = default;
- void add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn);
- void add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type);
- void add_static(bool is_public, bool is_specialisable, ::std::string name, Static v);
+ void add_function(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Function fcn);
+ void add_type(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, TypeRef type);
+ void add_static(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Static v);
void add_macro_invocation( MacroInvocation inv );
const ImplDef& def() const { return m_def; }
@@ -449,28 +458,25 @@ public:
const ::std::vector<ImplItem>& items() const { return m_items; }
::std::vector<ImplItem>& items() { return m_items; }
- bool has_named_item(const ::std::string& name) const;
+ bool has_named_item(const RcString& name) const;
friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl);
private:
};
-struct UseStmt
+struct UseItem
{
- Span sp;
- ::AST::Path path;
- ::AST::PathBinding alt_binding;
-
- UseStmt(Span sp, Path p):
- sp(sp),
- path(p)
- {
- }
-
- UseStmt clone() const;
+ Span sp; // Span covering the entire `use foo;`
+ struct Ent {
+ Span sp; // Span covering just the path (final component)
+ ::AST::Path path;
+ RcString name; // If "", this is a glob/wildcard use
+ };
+ ::std::vector<Ent> entries;
- friend ::std::ostream& operator<<(::std::ostream& os, const UseStmt& x);
+ UseItem clone() const;
+ //friend ::std::ostream& operator<<(::std::ostream& os, const UseItem& x);
};
class ExternBlock
@@ -512,7 +518,11 @@ public:
struct FileInfo
{
bool controls_dir = false;
+ bool force_no_load = false;
+ // Path to this module
::std::string path = "!";
+ // Directory controlled by this module
+ ::std::string dir = "";
};
FileInfo m_file_info;
@@ -526,13 +536,26 @@ public:
};
// TODO: Document difference between namespace and Type
- ::std::unordered_map< ::std::string, IndexEnt > m_namespace_items;
- ::std::unordered_map< ::std::string, IndexEnt > m_type_items;
- ::std::unordered_map< ::std::string, IndexEnt > m_value_items;
+ ::std::unordered_map< RcString, IndexEnt > m_namespace_items;
+ ::std::unordered_map< RcString, IndexEnt > m_type_items;
+ ::std::unordered_map< RcString, IndexEnt > m_value_items;
// List of macros imported from other modules (via #[macro_use], includes proc macros)
// - First value is an absolute path to the macro (including crate name)
- ::std::vector<::std::pair< ::std::vector<::std::string>, const MacroRules* >> m_macro_imports;
+ struct MacroImport {
+ bool is_pub;
+ RcString name; // Can be different, if `use foo as bar` is used
+ ::std::vector<RcString> path; // includes the crate name
+ const MacroRules* macro_ptr;
+ };
+ ::std::vector<MacroImport> m_macro_imports;
+
+ struct Import {
+ bool is_pub;
+ RcString name;
+ ::AST::Path path; // If `name` is "", then this is a module/enum to glob
+ };
+ ::std::vector<Import> m_item_imports;
public:
Module() {}
@@ -542,20 +565,19 @@ public:
}
bool is_anon() const {
- return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name()[0] == '#';
+ return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name().c_str()[0] == '#';
}
/// Create an anon module (for use inside expressions)
::std::shared_ptr<AST::Module> add_anon();
void add_item(Named<Item> item);
- void add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs);
- void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs);
- void add_alias(bool is_public, UseStmt path, ::std::string name, AttributeList attrs);
+ void add_item(Span sp, bool is_pub, RcString name, Item it, AttributeList attrs);
+ void add_ext_crate(Span sp, bool is_pub, RcString ext_name, RcString imp_name, AttributeList attrs);
void add_macro_invocation(MacroInvocation item);
- void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro);
- void add_macro_import(::std::string name, const MacroRules& mr);
+ void add_macro(bool is_exported, RcString name, MacroRulesPtr macro);
+ void add_macro_import(RcString name, const MacroRules& mr);
@@ -571,25 +593,24 @@ public:
NamedList<MacroRulesPtr>& macros() { return m_macros; }
const NamedList<MacroRulesPtr>& macros() const { return m_macros; }
const ::std::vector<Named<const MacroRules*> > macro_imports_res() const { return m_macro_import_res; }
-
-private:
- void resolve_macro_import(const Crate& crate, const ::std::string& modname, const ::std::string& macro_name);
};
TAGGED_UNION_EX(Item, (), None,
(
(None, struct {} ),
(MacroInv, MacroInvocation),
- (Use, UseStmt),
+ // TODO: MacroDefinition
+ (Use, UseItem),
// Nameless items
(ExternBlock, ExternBlock),
(Impl, Impl),
(NegImpl, ImplDef),
+ (Macro, MacroRulesPtr),
(Module, Module),
(Crate, struct {
- ::std::string name;
+ RcString name;
}),
(Type, TypeAlias),
@@ -602,12 +623,8 @@ TAGGED_UNION_EX(Item, (), None,
(Static, Static)
),
- (, attrs(mv$(x.attrs))), (attrs = mv$(x.attrs);),
+ (), (),
(
- public:
- AttributeList attrs;
- Span span;
-
Item clone() const;
)
);
diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp
index 0e1c8149..7a6ce864 100644
--- a/src/ast/attrs.hpp
+++ b/src/ast/attrs.hpp
@@ -8,6 +8,7 @@
#ifndef _AST_ATTRS_HPP_
#define _AST_ATTRS_HPP_
+#include <tagged_union.hpp>
namespace AST {
@@ -74,23 +75,24 @@ TAGGED_UNION(AttributeData, None,
class Attribute
{
Span m_span;
- ::std::string m_name;
+ RcString m_name;
AttributeData m_data;
mutable bool m_is_used;
+ // TODO: Parse as a TT then expand?
public:
- Attribute(Span sp, ::std::string name):
+ Attribute(Span sp, RcString name):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_None({}) )
{
}
- Attribute(Span sp, ::std::string name, ::std::string str_val):
+ Attribute(Span sp, RcString name, ::std::string str_val):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_String({mv$(str_val)}) )
{
}
- Attribute(Span sp, ::std::string name, ::std::vector<Attribute> items):
+ Attribute(Span sp, RcString name, ::std::vector<Attribute> items):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_List({mv$(items)}) )
@@ -122,7 +124,7 @@ public:
bool is_used() const { return m_is_used; }
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_name; }
+ const RcString& name() const { return m_name; }
const AttributeData& data() const { return m_data; }
// Legacy accessors/checkers
diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp
index 3db09f1b..19a19381 100644
--- a/src/ast/crate.cpp
+++ b/src/ast/crate.cpp
@@ -12,6 +12,12 @@
#include <hir/hir.hpp> // HIR::Crate
#include <hir/main_bindings.hpp> // HIR_Deserialise
#include <fstream>
+#ifdef _WIN32
+# define NOGDI // prevent ERROR from being defined
+# include <Windows.h>
+#else
+# include <dirent.h>
+#endif
::std::vector<::std::string> AST::g_crate_load_dirs = { };
::std::map<::std::string, ::std::string> AST::g_crate_overrides;
@@ -31,12 +37,13 @@ namespace {
fcn(mod);
for( auto& sm : mod.items() )
{
- TU_IFLET(::AST::Item, sm.data, Module, e,
- if( check_item_cfg(sm.data.attrs) )
+ if( auto* e = sm.data.opt_Module() )
+ {
+ if( check_item_cfg(sm.attrs) )
{
- iterate_module(e, fcn);
+ iterate_module(*e, fcn);
}
- )
+ }
}
// TODO: What about if an anon mod has been #[cfg]-d out?
// - For now, disable
@@ -60,12 +67,13 @@ void Crate::load_externs()
auto cb = [this](Module& mod) {
for( /*const*/ auto& it : mod.items() )
{
- TU_IFLET(AST::Item, it.data, Crate, c,
- if( check_item_cfg(it.data.attrs) )
+ if( auto* c = it.data.opt_Crate() )
+ {
+ if( check_item_cfg(it.attrs) )
{
- c.name = load_extern_crate( it.data.span, c.name );
+ c->name = load_extern_crate( it.span, c->name.c_str() );
}
- )
+ }
}
};
iterate_module(m_root_module, cb);
@@ -108,57 +116,134 @@ void Crate::load_externs()
}
// TODO: Handle disambiguating crates with the same name (e.g. libc in std and crates.io libc)
// - Crates recorded in rlibs should specify a hash/tag that's passed in to this function.
-::std::string Crate::load_extern_crate(Span sp, const ::std::string& name, const ::std::string& basename/*=""*/)
+RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::string& basename/*=""*/)
{
- DEBUG("Loading crate '" << name << "'");
+ TRACE_FUNCTION_F("Loading crate '" << name << "' (basename='" << basename << "')");
::std::string path;
- auto it = g_crate_overrides.find(name);
+ auto it = g_crate_overrides.find(name.c_str());
if(basename == "" && it != g_crate_overrides.end())
{
path = it->second;
if( !::std::ifstream(path).good() ) {
ERROR(sp, E0000, "Unable to open crate '" << name << "' at path " << path);
}
+ DEBUG("path = " << path << " (--extern)");
+ }
+ else if( basename != "" )
+ {
+#if 1
+ path = basename;
+#else
+ // Search a list of load paths for the crate
+ for(const auto& p : g_crate_load_dirs)
+ {
+ path = p + "/" + basename;
+
+ if( ::std::ifstream(path).good() ) {
+ break ;
+ }
+ }
+#endif
+ if( !::std::ifstream(path).good() ) {
+ ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories");
+ }
+ DEBUG("path = " << path << " (basename)");
}
else
{
+ ::std::vector<::std::string> paths;
+#define RLIB_SUFFIX ".rlib"
+#define RDYLIB_SUFFIX ".so"
+ auto direct_filename = FMT("lib" << name.c_str() << RLIB_SUFFIX);
+ auto direct_filename_so = FMT("lib" << name.c_str() << RDYLIB_SUFFIX);
+ auto name_prefix = FMT("lib" << name.c_str() << "-");
// Search a list of load paths for the crate
for(const auto& p : g_crate_load_dirs)
{
- if( basename == "" )
- {
- path = p + "/lib" + name + ".hir";
- // TODO: Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir)
+ path = p + "/" + direct_filename;
+ if( ::std::ifstream(path).good() ) {
+ paths.push_back(path);
}
- else
+ path = p + "/" + direct_filename_so;
+ if( ::std::ifstream(path).good() ) {
+ paths.push_back(path);
+ }
+ path = "";
+
+ // Search for `p+"/lib"+name+"-*.rlib" (which would match e.g. libnum-0.11.rlib)
+#ifdef _WIN32
+ WIN32_FIND_DATA find_data;
+ auto mask = p + "\\*";
+ HANDLE find_handle = FindFirstFile( mask.c_str(), &find_data );
+ if( find_handle == INVALID_HANDLE_VALUE ) {
+ continue ;
+ }
+ do
{
- path = p + "/" + basename;
+ const auto* fname = find_data.cFileName;
+#else
+ auto dp = opendir(p.c_str());
+ if( !dp ) {
+ continue ;
}
+ struct dirent *ent;
+ while( (ent = readdir(dp)) != nullptr && path == "" )
+ {
+ const auto* fname = ent->d_name;
+#endif
- if( ::std::ifstream(path).good() ) {
- break ;
+ // AND the start is "lib"+name
+ size_t len = strlen(fname);
+ if( len > (sizeof(RLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RLIB_SUFFIX)-1), RLIB_SUFFIX) == 0 )
+ {
+ }
+ else if( len > (sizeof(RDYLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RDYLIB_SUFFIX)-1), RDYLIB_SUFFIX) == 0 )
+ {
+ }
+ else
+ {
+ continue ;
+ }
+
+ DEBUG(fname << " vs " << name_prefix);
+ // Check if the entry ends with .rlib
+ if( strncmp(name_prefix.c_str(), fname, name_prefix.size()) != 0 )
+ continue ;
+
+ paths.push_back( p + "/" + fname );
+#ifdef _WIN32
+ } while( FindNextFile(find_handle, &find_data) );
+ FindClose(find_handle);
+#else
}
+ closedir(dp);
+#endif
+ if( paths.size() > 0 )
+ break;
}
- if( !::std::ifstream(path).good() ) {
- if( basename.empty() )
- ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories");
- else
- ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories");
+ if( paths.size() > 1 ) {
+ ERROR(sp, E0000, "Multiple options for crate '" << name << "' in search directories - " << paths);
+ }
+ if( paths.size() == 0 || !::std::ifstream(paths.front()).good() ) {
+ ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories");
}
+ path = paths.front();
+ DEBUG("path = " << path << " (search)");
}
// NOTE: Creating `ExternCrate` loads the crate from the specified path
auto ec = ExternCrate { name, path };
auto real_name = ec.m_hir->m_crate_name;
- assert(!real_name.empty());
+ assert(real_name != "");
auto res = m_extern_crates.insert(::std::make_pair( real_name, mv$(ec) ));
if( !res.second ) {
// Crate already loaded?
}
auto& ext_crate = res.first->second;
// Move the external list out (doesn't need to be kept in the nested crate)
- auto crate_ext_list = mv$( ext_crate.m_hir->m_ext_crates );
+ //auto crate_ext_list = mv$( ext_crate.m_hir->m_ext_crates );
+ const auto& crate_ext_list = ext_crate.m_hir->m_ext_crates;
// Load referenced crates
for( const auto& ext : crate_ext_list )
@@ -178,25 +263,26 @@ void Crate::load_externs()
return real_name;
}
-ExternCrate::ExternCrate(const ::std::string& name, const ::std::string& path):
+ExternCrate::ExternCrate(const RcString& name, const ::std::string& path):
m_name(name),
+ m_short_name(name),
m_filename(path)
{
TRACE_FUNCTION_F("name=" << name << ", path='" << path << "'");
- m_hir = HIR_Deserialise(path, name);
+ m_hir = HIR_Deserialise(path);
m_hir->post_load_update(name);
m_name = m_hir->m_crate_name;
}
-void ExternCrate::with_all_macros(::std::function<void(const ::std::string& , const MacroRules&)> cb) const
+void ExternCrate::with_all_macros(::std::function<void(const RcString& , const MacroRules&)> cb) const
{
for(const auto& m : m_hir->m_exported_macros)
{
cb(m.first, *m.second);
}
}
-const MacroRules* ExternCrate::find_macro_rules(const ::std::string& name) const
+const MacroRules* ExternCrate::find_macro_rules(const RcString& name) const
{
auto i = m_hir->m_exported_macros.find(name);
if(i != m_hir->m_exported_macros.end())
diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp
index 87a9f867..c4e1d5df 100644
--- a/src/ast/crate.hpp
+++ b/src/ast/crate.hpp
@@ -36,7 +36,7 @@ public:
class ProcMacroDef
{
public:
- ::std::string name;
+ RcString name;
::AST::Path path;
::std::vector<::std::string> attributes;
};
@@ -49,15 +49,16 @@ public:
::std::map< ::std::string, ::AST::Path> m_lang_items;
public:
Module m_root_module;
- ::std::map< ::std::string, ExternCrate> m_extern_crates;
+ ::std::map< RcString, ExternCrate> m_extern_crates;
// Mapping filled by searching for (?visible) macros with is_pub=true
- ::std::map< ::std::string, const MacroRules*> m_exported_macros;
+ ::std::map< RcString, const MacroRules*> m_exported_macros;
// List of tests (populated in expand if --test is passed)
bool m_test_harness = false;
::std::vector<TestDesc> m_tests;
- //::std::vector<::std::string> m_extra_files;
+ /// Files loaded using things like include! and include_str!
+ mutable ::std::vector<::std::string> m_extra_files;
// Procedural macros!
::std::vector<ProcMacroDef> m_proc_macros;
@@ -90,26 +91,27 @@ public:
/// Load the named crate and returns the crate's unique name
/// If the parameter `file` is non-empty, only that particular filename will be loaded (from any of the search paths)
- ::std::string load_extern_crate(Span sp, const ::std::string& name, const ::std::string& file="");
+ RcString load_extern_crate(Span sp, const RcString& name, const ::std::string& file="");
};
/// Representation of an imported crate
class ExternCrate
{
public:
- ::std::string m_name;
+ RcString m_name;
+ RcString m_short_name;
::std::string m_filename;
::HIR::CratePtr m_hir;
- ExternCrate(const ::std::string& name, const ::std::string& path);
+ ExternCrate(const RcString& name, const ::std::string& path);
ExternCrate(ExternCrate&&) = default;
ExternCrate& operator=(ExternCrate&&) = default;
ExternCrate(const ExternCrate&) = delete;
ExternCrate& operator=(const ExternCrate& ) = delete;
- void with_all_macros(::std::function<void(const ::std::string& , const MacroRules&)> cb) const;
- const MacroRules* find_macro_rules(const ::std::string& name) const;
+ void with_all_macros(::std::function<void(const RcString& , const MacroRules&)> cb) const;
+ const MacroRules* find_macro_rules(const RcString& name) const;
};
extern ::std::vector<::std::string> g_crate_load_dirs;
diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp
index f1481abf..4e880a76 100644
--- a/src/ast/dump.cpp
+++ b/src/ast/dump.cpp
@@ -36,7 +36,7 @@ public:
void handle_enum(const AST::Enum& s);
void handle_trait(const AST::Trait& s);
- void handle_function(bool is_pub, const ::std::string& name, const AST::Function& f);
+ void handle_function(bool is_pub, const RcString& name, const AST::Function& f);
virtual bool is_const() const override { return true; }
virtual void visit(AST::ExprNode_Block& n) override {
@@ -71,6 +71,10 @@ public:
dec_indent();
m_os << indent() << "}";
}
+ virtual void visit(AST::ExprNode_Try& n) override {
+ m_os << "try ";
+ AST::NodeVisitor::visit(n.m_inner);
+ }
virtual void visit(AST::ExprNode_Macro& n) override {
m_expr_root = false;
m_os << n.m_name << "!( /* TODO: Macro TT */ )";
@@ -619,17 +623,26 @@ void RustPrinter::handle_module(const AST::Module& mod)
// m_os << "\n";
// need_nl = false;
//}
- if( i_data.path == AST::Path() ) {
+ if( i_data.entries.empty() ) {
continue ;
}
- m_os << indent() << (i.is_pub ? "pub " : "") << "use " << i_data;
- if( i.name == "" )
- {
- m_os << "::*";
+ m_os << indent() << (i.is_pub ? "pub " : "") << "use ";
+ if( i_data.entries.size() > 1 ) {
+ m_os << "{";
}
- else if( i_data.path.nodes().back().name() != i.name )
+ for(const auto& ent : i_data.entries)
{
- m_os << " as " << i.name;
+ if( &ent != &i_data.entries.front() )
+ m_os << ", ";
+ m_os << ent.path;
+ if( ent.name == "" ) {
+ m_os << "::*";
+ }
+ else if( ent.name != ent.path.nodes().back().name() ) {
+ m_os << " as " << ent.name;
+ }
+ else {
+ }
}
m_os << ";\n";
}
@@ -640,7 +653,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
if( !item.data.is_Crate() ) continue ;
const auto& e = item.data.as_Crate();
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << "extern crate \"" << e.name << "\" as " << item.name << ";\n";
}
@@ -649,7 +662,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
if( !item.data.is_ExternBlock() ) continue ;
const auto& e = item.data.as_ExternBlock();
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << "extern \"" << e.abi() << "\" {}\n";
}
@@ -677,7 +690,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
m_os << "\n";
need_nl = false;
}
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "type " << item.name;
print_params(e.params());
m_os << " = " << e.type();
@@ -692,7 +705,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Struct();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "struct " << item.name;
handle_struct(e);
}
@@ -703,7 +716,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Enum();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "enum " << item.name;
handle_enum(e);
}
@@ -714,7 +727,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Trait();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "trait " << item.name;
handle_trait(e);
}
@@ -728,7 +741,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
m_os << "\n";
need_nl = false;
}
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "");
switch( e.s_class() )
{
@@ -747,7 +760,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Function();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
handle_function(item.is_pub, item.name, e);
}
@@ -1029,7 +1042,7 @@ void RustPrinter::handle_struct(const AST::Struct& s)
(Tuple,
m_os << "(";
for( const auto& i : e.ents )
- m_os << i.m_type << ", ";
+ m_os << (i.m_is_public ? "pub " : "") << i.m_type << ", ";
m_os << ")\n";
print_bounds(s.params());
m_os << indent() << ";\n";
@@ -1120,7 +1133,7 @@ void RustPrinter::handle_trait(const AST::Trait& s)
m_os << "\n";
}
-void RustPrinter::handle_function(bool is_pub, const ::std::string& name, const AST::Function& f)
+void RustPrinter::handle_function(bool is_pub, const RcString& name, const AST::Function& f)
{
m_os << indent();
m_os << (is_pub ? "pub " : "");
diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp
index 1525ed12..dc006212 100644
--- a/src/ast/expr.cpp
+++ b/src/ast/expr.cpp
@@ -93,6 +93,12 @@ NODE(ExprNode_Block, {
return NEWNODE(ExprNode_Block, m_is_unsafe, m_yields_final_value, mv$(nodes), m_local_mod);
})
+NODE(ExprNode_Try, {
+ os << "try " << *m_inner;
+},{
+ return NEWNODE(ExprNode_Try, m_inner->clone());
+})
+
NODE(ExprNode_Macro, {
os << m_name << "!";
if( m_ident.size() > 0 )
@@ -358,7 +364,8 @@ NODE(ExprNode_Tuple, {
})
NODE(ExprNode_NamedValue, {
- os << m_path;
+ m_path.print_pretty(os, false);
+ //os << m_path;
},{
return NEWNODE(ExprNode_NamedValue, AST::Path(m_path));
})
@@ -470,6 +477,9 @@ NV(ExprNode_Block, {
visit(child);
//UNINDENT();
})
+NV(ExprNode_Try, {
+ visit(node.m_inner);
+})
NV(ExprNode_Macro,
{
BUG(node.span(), "Hit unexpanded macro in expression - " << node);
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 264b37e9..6cfda001 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -74,14 +74,27 @@ struct ExprNode_Block:
NODE_METHODS();
};
+struct ExprNode_Try:
+ public ExprNode
+{
+ ExprNodeP m_inner;
+
+ ExprNode_Try(ExprNodeP inner):
+ m_inner(mv$(inner))
+ {
+ }
+
+ NODE_METHODS();
+};
+
struct ExprNode_Macro:
public ExprNode
{
- ::std::string m_name;
- ::std::string m_ident;
+ RcString m_name;
+ RcString m_ident;
::TokenTree m_tokens;
- ExprNode_Macro(::std::string name, ::std::string ident, ::TokenTree&& tokens):
+ ExprNode_Macro(RcString name, RcString ident, ::TokenTree&& tokens):
m_name(name),
m_ident(ident),
m_tokens( move(tokens) )
@@ -127,10 +140,10 @@ struct ExprNode_Flow:
CONTINUE,
BREAK,
} m_type;
- ::std::string m_target;
+ RcString m_target;
unique_ptr<ExprNode> m_value;
- ExprNode_Flow(Type type, ::std::string target, unique_ptr<ExprNode>&& value):
+ ExprNode_Flow(Type type, RcString target, unique_ptr<ExprNode>&& value):
m_type(type),
m_target( move(target) ),
m_value( move(value) )
@@ -232,24 +245,24 @@ struct ExprNode_Loop:
WHILELET,
FOR,
} m_type;
- ::std::string m_label;
+ RcString m_label;
AST::Pattern m_pattern;
unique_ptr<ExprNode> m_cond; // if NULL, loop is a 'loop'
unique_ptr<ExprNode> m_code;
ExprNode_Loop(): m_type(LOOP) {}
- ExprNode_Loop(::std::string label, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, unique_ptr<ExprNode> code):
m_type(LOOP),
m_label( ::std::move(label) ),
m_code( ::std::move(code) )
{}
- ExprNode_Loop(::std::string label, unique_ptr<ExprNode> cond, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, unique_ptr<ExprNode> cond, unique_ptr<ExprNode> code):
m_type(WHILE),
m_label( ::std::move(label) ),
m_cond( ::std::move(cond) ),
m_code( ::std::move(code) )
{}
- ExprNode_Loop(::std::string label, Type type, AST::Pattern pattern, unique_ptr<ExprNode> val, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, Type type, AST::Pattern pattern, unique_ptr<ExprNode> val, unique_ptr<ExprNode> code):
m_type(type),
m_label( ::std::move(label) ),
m_pattern( ::std::move(pattern) ),
@@ -417,7 +430,7 @@ struct ExprNode_StructLiteral:
{
struct Ent {
AttributeList attrs;
- ::std::string name;
+ RcString name;
unique_ptr<ExprNode> value;
};
typedef ::std::vector<Ent> t_values;
@@ -480,9 +493,9 @@ struct ExprNode_Field:
public ExprNode
{
::std::unique_ptr<ExprNode> m_obj;
- ::std::string m_name;
+ RcString m_name;
- ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, ::std::string name):
+ ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, RcString name):
m_obj( ::std::move(obj) ),
m_name( ::std::move(name) )
{
@@ -634,6 +647,7 @@ public:
virtual void visit(nt& node) = 0/*; \
virtual void visit(const nt& node) = 0*/
NT(ExprNode_Block);
+ NT(ExprNode_Try);
NT(ExprNode_Macro);
NT(ExprNode_Asm);
NT(ExprNode_Flow);
@@ -679,6 +693,7 @@ public:
virtual void visit(nt& node) override;/* \
virtual void visit(const nt& node) override*/
NT(ExprNode_Block);
+ NT(ExprNode_Try);
NT(ExprNode_Macro);
NT(ExprNode_Asm);
NT(ExprNode_Flow);
diff --git a/src/ast/expr_ptr.hpp b/src/ast/expr_ptr.hpp
index cae519cc..022c548a 100644
--- a/src/ast/expr_ptr.hpp
+++ b/src/ast/expr_ptr.hpp
@@ -23,6 +23,7 @@ public:
Expr(ExprNode* node);
Expr();
+ operator bool() const { return is_valid(); }
bool is_valid() const { return m_node.get() != nullptr; }
const ExprNode& node() const { assert(m_node.get()); return *m_node; }
ExprNode& node() { assert(m_node.get()); return *m_node; }
diff --git a/src/ast/generics.hpp b/src/ast/generics.hpp
index c222044c..bfc7080b 100644
--- a/src/ast/generics.hpp
+++ b/src/ast/generics.hpp
@@ -17,7 +17,7 @@ class TypeParam
::AST::AttributeList m_attrs;
Span m_span;
// TODO: use an Ident?
- ::std::string m_name;
+ RcString m_name;
::TypeRef m_default;
public:
TypeParam(TypeParam&& x) = default;
@@ -30,7 +30,7 @@ public:
{
}
- TypeParam(Span sp, ::AST::AttributeList attrs, ::std::string name):
+ TypeParam(Span sp, ::AST::AttributeList attrs, RcString name):
m_attrs( ::std::move(attrs) ),
m_span( ::std::move(sp) ),
m_name( ::std::move(name) ),
@@ -44,7 +44,7 @@ public:
const ::AST::AttributeList& attrs() const { return m_attrs; }
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_name; }
+ const RcString& name() const { return m_name; }
const TypeRef& get_default() const { return m_default; }
TypeRef& get_default() { return m_default; }
diff --git a/src/ast/item.hpp b/src/ast/item.hpp
index 0074ce9a..a5b0b1a5 100644
--- a/src/ast/item.hpp
+++ b/src/ast/item.hpp
@@ -9,15 +9,18 @@
#include <string>
#include <vector>
+#include "attrs.hpp"
namespace AST {
template <typename T>
struct Named
{
- ::std::string name;
- T data;
+ Span span;
+ AttributeList attrs;
bool is_pub;
+ RcString name;
+ T data;
Named():
is_pub(false)
@@ -25,10 +28,12 @@ struct Named
Named(Named&&) = default;
Named(const Named&) = default;
Named& operator=(Named&&) = default;
- Named(::std::string name, T data, bool is_pub):
+ Named(Span sp, AttributeList attrs, bool is_pub, RcString name, T data):
+ span(sp),
+ attrs( ::std::move(attrs) ),
+ is_pub( is_pub ),
name( ::std::move(name) ),
- data( ::std::move(data) ),
- is_pub( is_pub )
+ data( ::std::move(data) )
{
}
};
diff --git a/src/ast/macro.hpp b/src/ast/macro.hpp
index 5b2223ce..e94de8f1 100644
--- a/src/ast/macro.hpp
+++ b/src/ast/macro.hpp
@@ -18,8 +18,8 @@ class MacroInvocation
{
Span m_span;
- ::std::string m_macro_name;
- ::std::string m_ident;
+ RcString m_macro_name;
+ RcString m_ident;
TokenTree m_input;
public:
MacroInvocation(MacroInvocation&&) = default;
@@ -31,7 +31,7 @@ public:
{
}
- MacroInvocation(Span span, ::std::string macro, ::std::string ident, TokenTree input):
+ MacroInvocation(Span span, RcString macro, RcString ident, TokenTree input):
m_span( mv$(span) ),
m_macro_name( mv$(macro) ),
m_ident( mv$(ident) ),
@@ -48,9 +48,9 @@ public:
}
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_macro_name; }
+ const RcString& name() const { return m_macro_name; }
- const ::std::string& input_ident() const { return m_ident; }
+ const RcString& input_ident() const { return m_ident; }
const TokenTree& input_tt() const { return m_input; }
TokenTree& input_tt() { return m_input; }
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index 6fdf1e40..830e7372 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -17,8 +17,8 @@
namespace AST {
// --- AST::PathBinding
-::std::ostream& operator<<(::std::ostream& os, const PathBinding& x) {
- TU_MATCH(PathBinding, (x), (i),
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x) {
+ TU_MATCHA( (x), (i),
(Unbound, os << "_"; ),
(Crate , os << "Crate"; ),
(Module, os << "Module"; ),
@@ -26,39 +26,80 @@ namespace AST {
(Struct, os << "Struct"; ),
(Enum, os << "Enum"; ),
(Union, os << "Union"; ),
+ (EnumVar, os << "EnumVar(" << i.idx << ")"; ),
+ (TypeAlias, os << "TypeAlias";),
+ (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; )
+ )
+ return os;
+}
+PathBinding_Type PathBinding_Type::clone() const
+{
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Type::make_Unbound({}); ),
+ (Module , return PathBinding_Type::make_Module(e); ),
+ (Crate , return PathBinding_Type(e); ),
+ (Trait , return PathBinding_Type(e); ),
+ (Struct , return PathBinding_Type(e); ),
+ (Enum , return PathBinding_Type(e); ),
+ (Union , return PathBinding_Type(e); ),
+ (TypeAlias, return PathBinding_Type::make_TypeAlias(e); ),
+ (EnumVar , return PathBinding_Type::make_EnumVar(e); ),
+
+ (TypeParameter, return PathBinding_Type::make_TypeParameter(e); )
+ )
+ throw "BUG: Fell off the end of PathBinding_Type::clone";
+}
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x) {
+ TU_MATCHA( (x), (i),
+ (Unbound, os << "_"; ),
+ (Struct, os << "Struct"; ),
(Static, os << "Static"; ),
(Function, os << "Function";),
(EnumVar, os << "EnumVar(" << i.idx << ")"; ),
- (TypeAlias, os << "TypeAlias";),
- (StructMethod, os << "StructMethod"; ),
- (TraitMethod, os << "TraitMethod"; ),
-
- (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; ),
(Variable, os << "Var(" << i.slot << ")"; )
)
return os;
}
-PathBinding PathBinding::clone() const
+PathBinding_Value PathBinding_Value::clone() const
{
- TU_MATCH(::AST::PathBinding, (*this), (e),
- (Unbound , return PathBinding::make_Unbound({}); ),
- (Module , return PathBinding::make_Module(e); ),
- (Crate , return PathBinding(e); ),
- (Trait , return PathBinding(e); ),
- (Struct , return PathBinding(e); ),
- (Enum , return PathBinding(e); ),
- (Union , return PathBinding(e); ),
- (Static , return PathBinding(e); ),
- (Function, return PathBinding(e); ),
- (TypeAlias, return PathBinding::make_TypeAlias(e); ),
- (EnumVar , return PathBinding::make_EnumVar(e); ),
- (StructMethod, return PathBinding::make_StructMethod(e); ),
- (TraitMethod, return PathBinding::make_TraitMethod(e); ),
-
- (TypeParameter, return PathBinding::make_TypeParameter(e); ),
- (Variable, return PathBinding::make_Variable(e); )
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Value::make_Unbound({}); ),
+ (Struct , return PathBinding_Value(e); ),
+ (Static , return PathBinding_Value(e); ),
+ (Function, return PathBinding_Value(e); ),
+ (EnumVar , return PathBinding_Value::make_EnumVar(e); ),
+ (Variable, return PathBinding_Value::make_Variable(e); )
)
- throw "BUG: Fell off the end of PathBinding::clone";
+ throw "BUG: Fell off the end of PathBinding_Value::clone";
+}
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x) {
+ TU_MATCHA( (x), (i),
+ (Unbound, os << "_"; ),
+ (ProcMacroDerive,
+ os << "ProcMacroDerive(? " << i.mac_name << ")";
+ ),
+ (ProcMacroAttribute,
+ os << "ProcMacroAttribute(? " << i.mac_name << ")";
+ ),
+ (ProcMacro,
+ os << "ProcMacro(? " << i.mac_name << ")";
+ ),
+ (MacroRules,
+ os << "MacroRules(? ?)";
+ )
+ )
+ return os;
+}
+PathBinding_Macro PathBinding_Macro::clone() const
+{
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Macro::make_Unbound({}); ),
+ (ProcMacroDerive, return PathBinding_Macro(e); ),
+ (ProcMacroAttribute, return PathBinding_Macro(e); ),
+ (ProcMacro, return PathBinding_Macro(e); ),
+ (MacroRules, return PathBinding_Macro(e); )
+ )
+ throw "BUG: Fell off the end of PathBinding_Macro::clone";
}
::std::ostream& operator<<(::std::ostream& os, const PathParams& x)
@@ -68,7 +109,7 @@ PathBinding PathBinding::clone() const
for(const auto& v : x.m_lifetimes) {
if(needs_comma) os << ", ";
needs_comma = true;
- os << "'" << v;
+ os << v;
}
for(const auto& v : x.m_types) {
if(needs_comma) os << ", ";
@@ -107,7 +148,7 @@ Ordering PathParams::ord(const PathParams& x) const
}
// --- AST::PathNode
-PathNode::PathNode(::std::string name, PathParams args):
+PathNode::PathNode(RcString name, PathParams args):
m_name( mv$(name) ),
m_params( mv$(args) )
{
@@ -159,8 +200,10 @@ AST::Path::Path(TagUfcs, TypeRef type, Path trait, ::std::vector<AST::PathNode>
}
AST::Path::Path(const Path& x):
m_class()
- //m_binding(x.m_binding)
+ //,m_bindings(x.m_bindings)
{
+ memcpy(&m_bindings, &x.m_bindings, sizeof(Bindings));
+
TU_MATCH(Class, (x.m_class), (ent),
(Invalid, m_class = Class::make_Invalid({});),
(Local,
@@ -185,15 +228,35 @@ AST::Path::Path(const Path& x):
m_class = Class::make_UFCS({ box$(ent.type->clone()), nullptr, ent.nodes });
)
)
+}
+
+bool Path::is_parent_of(const Path& x) const
+{
+ if( !this->m_class.is_Absolute() || !x.m_class.is_Absolute() )
+ return false;
+ const auto& te = this->m_class.as_Absolute();
+ const auto& xe = x.m_class.as_Absolute();
+
+ if( te.crate != xe.crate )
+ return false;
- memcpy(&m_binding, &x.m_binding, sizeof(PathBinding));
+ if( te.nodes.size() > xe.nodes.size() )
+ return false;
+
+ for(size_t i = 0; i < te.nodes.size(); i ++)
+ {
+ if( te.nodes[i].name() != xe.nodes[i].name() )
+ return false;
+ }
+
+ return true;
}
void Path::bind_variable(unsigned int slot)
{
- m_binding = PathBinding::make_Variable({slot});
+ m_bindings.value = PathBinding_Value::make_Variable({slot});
}
-void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& /*args*/)
+void Path::bind_enum_var(const Enum& ent, const RcString& name)
{
auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; });
if( it == ent.variants().end() )
@@ -203,10 +266,8 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std
unsigned int idx = it - ent.variants().begin();
DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")");
- ::AST::PathBinding::Data_EnumVar tmp = {};
- tmp.enum_ = &ent;
- tmp.idx = idx;
- m_binding = PathBinding::make_EnumVar( mv$(tmp) );
+ m_bindings.type = PathBinding_Type::make_EnumVar({ &ent, idx });
+ m_bindings.value = PathBinding_Value::make_EnumVar({ &ent, idx });
}
Path& Path::operator+=(const Path& other)
@@ -214,7 +275,7 @@ Path& Path::operator+=(const Path& other)
for(auto& node : other.nodes())
append(node);
// If the path is modified, clear the binding
- m_binding = PathBinding();
+ m_bindings = Bindings();
return *this;
}
@@ -268,13 +329,13 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug)
),
(Local,
// Only print comment if there's no binding
- if( m_binding.is_Unbound() )
+ if( m_bindings.value.is_Unbound() )
{
if( is_debug )
os << "/*var*/";
}
else
- assert( m_binding.is_Variable() );
+ assert( m_bindings.value.is_Variable() );
os << ent.name;
),
(Relative,
@@ -334,8 +395,29 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug)
}
)
)
- if( is_debug )
- os << "/*" << m_binding << "*/";
+ if( is_debug ) {
+ os << "/*";
+ bool printed = false;
+ if( !m_bindings.value.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "v:" << m_bindings.value;
+ printed = true;
+ }
+ if( !m_bindings.type.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "t:" << m_bindings.type;
+ printed = true;
+ }
+ if( !m_bindings.macro.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "m:" << m_bindings.macro;
+ printed = true;
+ }
+ if( !printed ) {
+ os << "?";
+ }
+ os << "*/";
+ }
}
::std::ostream& operator<<(::std::ostream& os, const Path& path)
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index c2d13d73..c611c819 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -20,6 +20,7 @@
#include "../include/ident.hpp"
class TypeRef;
+class MacroRules;
namespace HIR {
class Module;
@@ -45,7 +46,36 @@ class Static;
class Function;
class ExternCrate;
-TAGGED_UNION_EX(PathBinding, (), Unbound, (
+TAGGED_UNION_EX(PathBinding_Value, (), Unbound, (
+ (Unbound, struct {
+ }),
+ (Struct, struct {
+ const Struct* struct_;
+ const ::HIR::Struct* hir;
+ }),
+ (Static, struct {
+ const Static* static_;
+ const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const`
+ }),
+ (Function, struct {
+ const Function* func_;
+ }),
+ (EnumVar, struct {
+ const Enum* enum_;
+ unsigned int idx;
+ const ::HIR::Enum* hir;
+ }),
+ (Variable, struct {
+ unsigned int slot;
+ })
+ ),
+ (), (),
+ (
+ public:
+ PathBinding_Value clone() const;
+ )
+ );
+TAGGED_UNION_EX(PathBinding_Type, (), Unbound, (
(Unbound, struct {
}),
(Crate, struct {
@@ -71,13 +101,7 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, (
const Trait* trait_;
const ::HIR::Trait* hir;
}),
- (Static, struct {
- const Static* static_;
- const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const`
- }),
- (Function, struct {
- const Function* func_;
- }),
+
(EnumVar, struct {
const Enum* enum_;
unsigned int idx;
@@ -86,42 +110,59 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, (
(TypeAlias, struct {
const TypeAlias* alias_;
}),
- (StructMethod, struct {
- const Struct* struct_;
- ::std::string name;
- }),
- (TraitMethod, struct {
- const Trait* trait_;
- ::std::string name;
- }),
(TypeParameter, struct {
unsigned int level;
unsigned int idx;
+ })
+ ),
+ (), (),
+ (
+ public:
+ PathBinding_Type clone() const;
+ )
+ );
+TAGGED_UNION_EX(PathBinding_Macro, (), Unbound, (
+ (Unbound, struct {
}),
- (Variable, struct {
- unsigned int slot;
+ (ProcMacroDerive, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (ProcMacroAttribute, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (ProcMacro, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (MacroRules, struct {
+ const ExternCrate* crate_; // Can be NULL
+ const MacroRules* mac;
})
),
(), (),
(
public:
- PathBinding clone() const;
+ PathBinding_Macro clone() const;
)
);
-extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x);
struct PathParams
{
::std::vector< LifetimeRef > m_lifetimes;
::std::vector< TypeRef > m_types;
- ::std::vector< ::std::pair< ::std::string, TypeRef> > m_assoc;
+ ::std::vector< ::std::pair< RcString, TypeRef> > m_assoc;
PathParams(PathParams&& x) = default;
PathParams(const PathParams& x);
PathParams() {}
- PathParams(::std::vector<LifetimeRef> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<::std::string,TypeRef>> a):
+ PathParams(::std::vector<LifetimeRef> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<RcString,TypeRef>> a):
m_lifetimes(mv$(lfts)),
m_types(mv$(tys)),
m_assoc(mv$(a))
@@ -141,12 +182,12 @@ struct PathParams
class PathNode
{
- ::std::string m_name;
+ RcString m_name;
PathParams m_params;
public:
PathNode() {}
- PathNode(::std::string name, PathParams args = {});
- const ::std::string& name() const { return m_name; }
+ PathNode(RcString name, PathParams args = {});
+ const RcString& name() const { return m_name; }
const ::AST::PathParams& args() const { return m_params; }
::AST::PathParams& args() { return m_params; }
@@ -164,7 +205,7 @@ public:
TAGGED_UNION(Class, Invalid,
(Invalid, struct {}),
(Local, struct { // Variable / Type param (resolved)
- ::std::string name;
+ RcString name;
} ),
(Relative, struct { // General relative
Ident::Hygiene hygiene;
@@ -178,7 +219,7 @@ public:
::std::vector<PathNode> nodes;
} ),
(Absolute, struct { // Absolute
- ::std::string crate;
+ RcString crate;
::std::vector<PathNode> nodes;
} ),
(UFCS, struct { // Type-relative
@@ -191,27 +232,42 @@ public:
public:
Class m_class;
-private:
- PathBinding m_binding;
-public:
+ struct Bindings {
+ PathBinding_Value value;
+ PathBinding_Type type;
+ PathBinding_Macro macro;
+
+ Bindings clone() const {
+ return Bindings {
+ value.clone(), type.clone(), macro.clone()
+ };
+ }
+ bool has_binding() const {
+ return !value.is_Unbound() || !type.is_Unbound() || !macro.is_Unbound();
+ }
+ void merge_from(const Bindings& x) {
+ if(value.is_Unbound())
+ value = x.value.clone();
+ if(type.is_Unbound())
+ type = x.type.clone();
+ if(macro.is_Unbound())
+ macro = x.macro.clone();
+ }
+ } m_bindings;
+
virtual ~Path();
// INVALID
Path():
m_class()
{}
Path(Path&&) = default;
- Path& operator=(AST::Path&& x) {
- m_class = mv$(x.m_class);
- m_binding = mv$(x.m_binding);
- //DEBUG("Path, " << x);
- return *this;
- }
+ Path& operator=(AST::Path&& x) = default;
- Path(const Path& x);
+ /*explicit*/ Path(const Path& x);
Path& operator=(const AST::Path&) = delete;
// ABSOLUTE
- Path(::std::string crate, ::std::vector<PathNode> nodes):
+ Path(RcString crate, ::std::vector<PathNode> nodes):
m_class( Class::make_Absolute({ mv$(crate), mv$(nodes)}) )
{}
@@ -222,10 +278,10 @@ public:
// VARIABLE
struct TagLocal {};
- Path(TagLocal, ::std::string name):
+ Path(TagLocal, RcString name):
m_class( Class::make_Local({ mv$(name) }) )
{}
- Path(::std::string name):
+ Path(RcString name):
m_class( Class::make_Local({ mv$(name) }) )
{}
@@ -245,14 +301,6 @@ public:
m_class( Class::make_Super({ count, mv$(nodes) }) )
{}
- //void set_crate(::std::string crate) {
- // if( m_crate == "" ) {
- // m_crate = crate;
- // DEBUG("crate set to " << m_crate);
- // }
- //}
-
-
Class::Tag class_tag() const {
return m_class.tag();
}
@@ -262,7 +310,7 @@ public:
tmp.nodes().push_back( mv$(pn) );
return tmp;
}
- Path operator+(const ::std::string& s) const {
+ Path operator+(const RcString& s) const {
Path tmp = Path(*this);
tmp.append(PathNode(s, {}));
return tmp;
@@ -271,13 +319,17 @@ 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() );
//if( m_class.is_Invalid() )
// m_class = Class::make_Relative({});
nodes().push_back( mv$(node) );
- m_binding = PathBinding();
+ m_bindings = Bindings();
}
bool is_trivial() const {
@@ -310,12 +362,9 @@ public:
)
throw ::std::runtime_error("Path::nodes() fell off");
}
- //const ::std::string& crate() const { return m_crate; }
- bool is_concrete() const;
+ bool is_parent_of(const Path& x) const;
- bool is_bound() const { return !m_binding.is_Unbound(); }
- const PathBinding& binding() const { return m_binding; }
void bind_variable(unsigned int slot);
::std::vector<PathNode>& nodes() {
@@ -349,14 +398,9 @@ private:
void check_param_counts(const GenericParams& params, bool expect_params, PathNode& node);
public:
- void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& args={});
- void bind_function(const Function& ent, const ::std::vector<TypeRef>& args={}) {
- (void)args;
- m_binding = PathBinding::make_Function({&ent});
- }
-
- void bind(::AST::PathBinding pb) {
- m_binding = mv$(pb);
+ void bind_enum_var(const Enum& ent, const RcString& name);
+ void bind_function(const Function& ent) {
+ m_bindings.value = PathBinding_Value::make_Function({&ent});
}
};
diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp
index 72087d95..e13662fe 100644
--- a/src/ast/pattern.cpp
+++ b/src/ast/pattern.cpp
@@ -223,7 +223,7 @@ AST::Pattern AST::Pattern::clone() const
rv.m_data = Data::make_StructTuple({ ::AST::Path(e.path), H::clone_tup(e.tup_pat) });
),
(Struct,
- ::std::vector< ::std::pair< ::std::string, Pattern> > sps;
+ ::std::vector< ::std::pair< RcString, Pattern> > sps;
for(const auto& sp : e.sub_patterns)
sps.push_back( ::std::make_pair(sp.first, sp.second.clone()) );
rv.m_data = Data::make_Struct({ ::AST::Path(e.path), mv$(sps) });
diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp
index 40cfa927..81c1126a 100644
--- a/src/ast/pattern.hpp
+++ b/src/ast/pattern.hpp
@@ -88,7 +88,7 @@ public:
(Value, struct { Value start; Value end; } ),
(Tuple, TuplePat ),
(StructTuple, struct { Path path; TuplePat tup_pat; } ),
- (Struct, struct { Path path; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; } ),
+ (Struct, struct { Path path; ::std::vector< ::std::pair< RcString, Pattern> > sub_patterns; bool is_exhaustive; } ),
(Slice, struct { ::std::vector<Pattern> sub_pats; }),
(SplitSlice, struct { ::std::vector<Pattern> leading; PatternBinding extra_bind; ::std::vector<Pattern> trailing; } )
);
@@ -171,7 +171,7 @@ public:
{}
struct TagStruct {};
- Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive):
+ Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< RcString,Pattern> > sub_patterns, bool is_exhaustive):
m_span( mv$(sp) ),
m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) )
{}
diff --git a/src/ast/types.cpp b/src/ast/types.cpp
index 98bc6ee1..496cf694 100644
--- a/src/ast/types.cpp
+++ b/src/ast/types.cpp
@@ -40,13 +40,14 @@ static const struct {
{"usize", CORETYPE_UINT},
};
-enum eCoreType coretype_fromstring(const ::std::string& name)
+enum eCoreType coretype_fromstring(const char* name)
{
for(unsigned int i = 0; i < sizeof(CORETYPES)/sizeof(CORETYPES[0]); i ++)
{
- if( name < CORETYPES[i].name )
+ int cmp = strcmp(name, CORETYPES[i].name);
+ if( cmp < 0 )
break;
- if( name == CORETYPES[i].name )
+ if( cmp == 0 )
return CORETYPES[i].type;
}
return CORETYPE_INVAL;
@@ -323,7 +324,7 @@ namespace AST {
os << "'_";
}
else {
- os << "'" << x.m_name;
+ os << "'" << x.m_name.name;
if( x.m_binding != LifetimeRef::BINDING_UNBOUND ) {
os << "/*" << x.m_binding << "*/";
}
diff --git a/src/ast/types.hpp b/src/ast/types.hpp
index af07ba2d..15cb1383 100644
--- a/src/ast/types.hpp
+++ b/src/ast/types.hpp
@@ -41,10 +41,12 @@ namespace AST {
class LifetimeRef
{
+ public:
static const uint16_t BINDING_STATIC = 0xFFFF;
static const uint16_t BINDING_UNBOUND = 0xFFFE;
static const uint16_t BINDING_INFER = 0xFFFD;
+ private:
Ident m_name;
uint16_t m_binding;
@@ -71,6 +73,7 @@ namespace AST {
bool is_infer() const { return m_binding == BINDING_INFER; }
const Ident& name() const { return m_name; }
+ uint16_t binding() const { return m_binding; }
Ordering ord(const LifetimeRef& x) const { return ::ord(m_name.name, x.m_name.name); }
bool operator==(const LifetimeRef& x) const { return ord(x) == OrdEqual; }
bool operator!=(const LifetimeRef& x) const { return ord(x) != OrdEqual; }
@@ -95,7 +98,7 @@ public:
struct TypeArgRef
{
- ::std::string name;
+ RcString name;
unsigned int level;
const AST::GenericParams* params;
};
@@ -163,7 +166,7 @@ TAGGED_UNION(TypeData, None,
::std::shared_ptr<AST::ExprNode> size;
}),
(Generic, struct {
- ::std::string name;
+ RcString name;
unsigned int index;
}),
(Path, struct {
@@ -274,11 +277,11 @@ public:
{}
struct TagArg {};
- TypeRef(TagArg, Span sp, ::std::string name, unsigned int binding = ~0u):
+ TypeRef(TagArg, Span sp, RcString name, unsigned int binding = ~0u):
m_span( mv$(sp) ),
m_data(TypeData::make_Generic({ name, binding }))
{}
- TypeRef(Span sp, ::std::string name, unsigned int binding = ~0u):
+ TypeRef(Span sp, RcString name, unsigned int binding = ~0u):
TypeRef(TagArg(), mv$(sp), mv$(name), binding)
{}
@@ -312,7 +315,7 @@ public:
AST::Path& path() { return m_data.as_Path().path; }
bool is_type_param() const { return m_data.is_Generic(); }
- const ::std::string& type_param() const { return m_data.as_Generic().name; }
+ const RcString& type_param() const { return m_data.as_Generic().name; }
bool is_reference() const { return m_data.is_Borrow(); }
bool is_pointer() const { return m_data.is_Pointer(); }
diff --git a/src/common.hpp b/src/common.hpp
index f46f93fd..0363c334 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -105,6 +105,10 @@ static inline Ordering ord(signed char l, signed char r)
{
return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
}
+static inline Ordering ord(int l, int r)
+{
+ return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
+}
static inline Ordering ord(short l, short r)
{
return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
@@ -244,6 +248,11 @@ inline Join<T> join(const char *sep, const ::std::vector<T> v) {
namespace std {
template <typename T>
+inline auto operator<<(::std::ostream& os, const T& v) -> decltype(v.fmt(os)) {
+ return v.fmt(os);
+}
+
+template <typename T>
inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T*>& v) {
if( v.size() > 0 )
{
@@ -403,5 +412,17 @@ RunIterable<T> runs(const ::std::vector<T>& x) {
return RunIterable<T>(x);
}
+template<typename T>
+class NullOnDrop {
+ T*& ptr;
+public:
+ NullOnDrop(T*& ptr):
+ ptr(ptr)
+ {}
+ ~NullOnDrop() {
+ ptr = nullptr;
+ }
+};
+
#endif
diff --git a/src/coretypes.hpp b/src/coretypes.hpp
index 7665f5ba..692473e5 100644
--- a/src/coretypes.hpp
+++ b/src/coretypes.hpp
@@ -24,7 +24,7 @@ enum eCoreType
CORETYPE_F64,
};
-extern enum eCoreType coretype_fromstring(const ::std::string& name);
+extern enum eCoreType coretype_fromstring(const char* name);
extern const char* coretype_name(const eCoreType ct);
#endif // CORETYPES_HPP_INCLUDED
diff --git a/src/debug.cpp b/src/debug.cpp
index 43e2795e..8a0d1f3c 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -11,7 +11,7 @@ TraceLog::TraceLog(const char* tag, ::std::function<void(::std::ostream&)> info_
m_tag(tag),
m_ret(ret)
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">> (";
info_cb(os);
@@ -23,7 +23,7 @@ TraceLog::TraceLog(const char* tag, ::std::function<void(::std::ostream&)> info_
m_tag(tag),
m_ret([](const auto&){})
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">> (";
info_cb(os);
@@ -35,7 +35,7 @@ TraceLog::TraceLog(const char* tag):
m_tag(tag),
m_ret([](const auto&){})
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">>" << ::std::endl;
}
@@ -43,7 +43,7 @@ TraceLog::TraceLog(const char* tag):
}
TraceLog::~TraceLog() {
UNINDENT();
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << "<< (";
m_ret(os);
diff --git a/src/expand/asm.cpp b/src/expand/asm.cpp
index d895c32d..90612758 100644
--- a/src/expand/asm.cpp
+++ b/src/expand/asm.cpp
@@ -35,12 +35,10 @@ namespace
class CAsmExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
auto lex = TTStream(sp, tt);
- if( ident != "" )
- ERROR(sp, E0000, "asm! doesn't take an ident");
auto template_text = get_string(sp, lex, crate, mod);
::std::vector<::AST::ExprNode_Asm::ValRef> outputs;
@@ -168,7 +166,7 @@ class CAsmExpander:
{
GET_TOK(tok, lex);
- if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "volatile" )
+ if( GET_TOK(tok, lex) == TOK_IDENT && tok.istr() == "volatile" )
{
flags.push_back( "volatile" );
}
diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp
new file mode 100644
index 00000000..ffba7b98
--- /dev/null
+++ b/src/expand/assert.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ // 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) );
+ toks.push_back( Token(TOK_EXCLAM) );
+
+ 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, RcString::new_interned("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, RcString::new_interned("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/cfg.cpp b/src/expand/cfg.cpp
index 773a38c4..3475b87b 100644
--- a/src/expand/cfg.cpp
+++ b/src/expand/cfg.cpp
@@ -60,7 +60,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
}
else if( mi.has_string() ) {
// Equaliy
- auto its = g_cfg_values.equal_range(mi.name());
+ auto its = g_cfg_values.equal_range(mi.name().c_str());
for(auto it = its.first; it != its.second; ++it)
{
DEBUG(""<<mi.name()<<": '"<<it->second<<"' == '"<<mi.string()<<"'");
@@ -70,7 +70,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
if( its.first != its.second )
return false;
- auto it2 = g_cfg_value_fcns.find(mi.name());
+ auto it2 = g_cfg_value_fcns.find(mi.name().c_str());
if(it2 != g_cfg_value_fcns.end() )
{
DEBUG(""<<mi.name()<<": ('"<<mi.string()<<"')?");
@@ -82,7 +82,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
}
else {
// Flag
- auto it = g_cfg_flags.find(mi.name());
+ auto it = g_cfg_flags.find(mi.name().c_str());
return (it != g_cfg_flags.end());
}
BUG(sp, "Fell off the end of check_cfg");
@@ -91,12 +91,8 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
class CCfgExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" ) {
- ERROR(sp, E0000, "cfg! doesn't take an identifier");
- }
-
auto lex = TTStream(sp, tt);
auto attrs = Parse_MetaItem(lex);
DEBUG("cfg!() - " << attrs);
@@ -126,7 +122,7 @@ class CCfgHandler:
crate.m_root_module.items().clear();
}
}
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
TRACE_FUNCTION_FR("#[cfg] item - " << mi, (i.is_None() ? "Deleted" : ""));
if( check_cfg(sp, mi) ) {
// Leave
diff --git a/src/expand/concat.cpp b/src/expand/concat.cpp
index 29a066df..bd741e2f 100644
--- a/src/expand/concat.cpp
+++ b/src/expand/concat.cpp
@@ -16,13 +16,11 @@
class CConcatExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
auto lex = TTStream(sp, tt);
- if( ident != "" )
- ERROR(sp, E0000, "format_args! doesn't take an ident");
::std::string rv;
do {
diff --git a/src/expand/crate_tags.cpp b/src/expand/crate_tags.cpp
index 0e7d8447..31bb8abd 100644
--- a/src/expand/crate_tags.cpp
+++ b/src/expand/crate_tags.cpp
@@ -15,10 +15,10 @@ public:
AttrStage stage() const override { return AttrStage::Pre; }
void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
- if( crate.m_crate_type != AST::Crate::Type::Unknown ) {
- //ERROR(sp, E0000, "Multiple #![crate_type] attributes");
- return ;
- }
+ //if( crate.m_crate_type != AST::Crate::Type::Unknown ) {
+ // //ERROR(sp, E0000, "Multiple #![crate_type] attributes");
+ // return ;
+ //}
if( !mi.has_string() ) {
ERROR(sp, E0000, "#![crate_type] requires a string argument");
}
@@ -42,9 +42,9 @@ public:
AttrStage stage() const override { return AttrStage::Pre; }
void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
- if( crate.m_crate_name != "" ) {
- ERROR(sp, E0000, "Multiple #![crate_name] attributes");
- }
+ //if( crate.m_crate_name != "" ) {
+ // ERROR(sp, E0000, "Multiple #![crate_name] attributes");
+ //}
if( !mi.has_string() || mi.string() == "" ) {
ERROR(sp, E0000, "#![crate_name] requires a non-empty string argument");
}
@@ -62,6 +62,14 @@ public:
// TODO: Check for an existing allocator crate
crate.m_lang_items.insert(::std::make_pair( "mrustc-allocator", AST::Path("",{}) ));
}
+
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
+ if( ! i.is_Function() ) {
+ ERROR(sp, E0000, "#[allocator] can only be put on functions and the crate - found on " << i.tag_str());
+ }
+ // TODO: Ensure that this is an extern { fn }
+ // TODO: Does this need to do anything?
+ }
};
class Decorator_PanicRuntime:
public ExpandDecorator
diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp
index 5bbef62c..a14a12a3 100644
--- a/src/expand/derive.cpp
+++ b/src/expand/derive.cpp
@@ -58,14 +58,98 @@ static inline ::std::vector<T> vec$(T v1, T v2, T v3, T v4, T v5) {
tmp.push_back( mv$(v5) );
return mv$(tmp);
}
+static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2)
+{
+ return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}) });
+}
+static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2, const char* c3)
+{
+ return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}), AST::PathNode(RcString::new_interned(c3), {}) });
+}
static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNodeP(en); }
//#define NEWNODE(type, ...) mk_exprnodep(new type(__VA_ARGS__))
#define NEWNODE(type, ...) mk_exprnodep(new AST::ExprNode_##type(__VA_ARGS__))
+static ::std::vector<AST::ExprNodeP> make_refpat_a(
+ const Span& sp,
+ ::std::vector<AST::Pattern>& pats_a,
+ const ::std::vector<TypeRef>& sub_types,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ for( size_t idx = 0; idx < sub_types.size(); idx ++ )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << idx));
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) );
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_a(
+ const Span& sp,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_a,
+ const ::std::vector<AST::StructItem>& fields,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ size_t idx = 0;
+ for( const auto& fld : fields )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) );
+ idx ++;
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_ab(
+ const Span& sp,
+ ::std::vector<AST::Pattern>& pats_a,
+ ::std::vector<AST::Pattern>& pats_b,
+ const ::std::vector<TypeRef>& sub_types,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ for( size_t idx = 0; idx < sub_types.size(); idx ++ )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << idx));
+ auto name_b = RcString::new_interned(FMT("b" << idx));
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) );
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_ab(
+ const Span& sp,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_a,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_b,
+ const ::std::vector<AST::StructItem>& fields,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ size_t idx = 0;
+ for( const auto& fld : fields )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
+ auto name_b = RcString::new_interned(FMT("b" << fld.m_name));
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) );
+ idx ++;
+ }
+ return nodes;
+}
+
+
struct DeriveOpts
{
- ::std::string core_name;
+ RcString core_name;
const ::std::vector<::AST::Attribute>& derive_items;
};
@@ -289,21 +373,20 @@ class Deriver_Debug:
// throw CompileError::Todo("derive(Debug) - _try");
//}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path debug_trait = AST::Path(core_name, { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) });
- TypeRef f_type(TypeRef::TagReference(), sp, AST::LifetimeRef(), true,
- TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})}))
- );
+ const AST::Path debug_trait = get_path(core_name, "fmt", "Debug");
AST::Function fcn(
sp,
AST::GenericParams(),
ABI_RUST, false, false, false,
- TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Result",{})}) ),
+ TypeRef(sp, get_path(core_name, "fmt", "Result")),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"), mv$(f_type) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"),
+ TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"),
+ TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, get_path(core_name, "fmt", "Formatter")) ) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
@@ -311,7 +394,7 @@ class Deriver_Debug:
AST::GenericParams params = get_params_with_bounds(sp, p, debug_trait, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, debug_trait), type.clone() ) );
- rv.add_function(false, false, "fmt", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "fmt", mv$(fcn));
return mv$(rv);
}
@@ -320,7 +403,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
- const ::std::string& name = type.path().nodes().back().name();
+ ::std::string name = type.path().nodes().back().name().c_str();
// Generate code for Debug
AST::ExprNodeP node;
@@ -338,12 +421,13 @@ public:
mv$(node), AST::PathNode("debug_struct",{}),
vec$( NEWNODE(String, name) )
);
+ // TODO: use a block instead of chaining
for( const auto& fld : e.ents )
{
node = NEWNODE(CallMethod,
mv$(node), AST::PathNode("field",{}),
vec$(
- NEWNODE(String, fld.m_name),
+ NEWNODE(String, fld.m_name.c_str()),
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF,
NEWNODE(Field,
NEWNODE(NamedValue, AST::Path("self")),
@@ -369,7 +453,7 @@ public:
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF,
NEWNODE(Field,
NEWNODE(NamedValue, AST::Path("self")),
- FMT(idx)
+ RcString::new_interned(FMT(idx))
)
))
)
@@ -397,61 +481,46 @@ public:
code = NEWNODE(CallMethod,
NEWNODE(NamedValue, AST::Path("f")),
AST::PathNode("write_str",{}),
- vec$( NEWNODE(String, v.m_name) )
+ vec$( NEWNODE(String, v.m_name.c_str()) )
);
pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- AST::ExprNodeP node;
- node = NEWNODE(NamedValue, AST::Path("f"));
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("debug_tuple",{}),
- vec$( NEWNODE(String, v.m_name) )
- );
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
-
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("field",{}),
- vec$(
- NEWNODE(NamedValue, AST::Path(name_a))
- )
- );
- }
-
- code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}), vec$( mv$(a) ));
+ });
+ nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp),
+ NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_tuple",{}),
+ vec$( NEWNODE(String, v.m_name.c_str()) )
+ )
+ ));
+ nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) );
+ code = NEWNODE(Block, mv$(nodes));
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- AST::ExprNodeP node;
-
- node = NEWNODE(NamedValue, AST::Path("f"));
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("debug_struct",{}),
- vec$( NEWNODE(String, v.m_name) )
- );
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
-
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("field",{}),
- vec$(
- NEWNODE(String, fld.m_name),
- NEWNODE(NamedValue, AST::Path(name_a))
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}),
+ vec$(
+ NEWNODE(String, e.m_fields[idx].m_name.c_str()),
+ mv$(a)
+ )
+ );
+ });
+ nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp),
+ NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_struct",{}),
+ vec$( NEWNODE(String, v.m_name.c_str()) )
)
- );
- }
+ ));
+ nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) );
- code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
+ code = NEWNODE(Block, mv$(nodes));
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
)
)
@@ -477,9 +546,9 @@ public:
class Deriver_PartialEq:
public Deriver
{
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialEq", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "PartialEq");
AST::Function fcn(
sp,
@@ -496,10 +565,10 @@ class Deriver_PartialEq:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "eq", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "eq", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(If,
NEWNODE(BinOp, AST::ExprNode_BinOp::CMPNEQU, mv$(v1), mv$(v2)),
@@ -529,7 +598,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -563,43 +632,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
- nodes.push_back(this->compare_and_ret(sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](auto idx, auto a, auto b){
+ return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( NEWNODE(Bool, true) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back(this->compare_and_ret(sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& name, auto a, auto b){
+ return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( NEWNODE(Bool, true) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -643,21 +694,12 @@ public:
class Deriver_PartialOrd:
public Deriver
{
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) });
- }
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) });
- }
-
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialOrd", {}) });
- const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "PartialOrd");
+ const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering");
- AST::Path path_option_ordering(core_name, { AST::PathNode("option", {}), AST::PathNode("Option", {}) });
+ AST::Path path_option_ordering = get_path(core_name, "option", "Option");
path_option_ordering.nodes().back().args().m_types.push_back( TypeRef(sp, path_ordering) );
AST::Function fcn(
@@ -675,14 +717,14 @@ class Deriver_PartialOrd:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "partial_cmp", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "partial_cmp", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(Match,
- NEWNODE(CallPath, this->get_path(core_name, "cmp", "PartialOrd", "partial_cmp"),
+ NEWNODE(CallPath, get_path(core_name, "cmp", "PartialOrd", "partial_cmp"),
::make_vec2(
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)),
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v2))
@@ -690,13 +732,13 @@ class Deriver_PartialOrd:
),
::make_vec3(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "option", "Option", "None")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "option", "Option", "None")) ),
nullptr,
- NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, this->get_path(core_name, "option", "Option", "None")))
+ NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, get_path(core_name, "option", "Option", "None")))
),
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, this->get_path(core_name, "option", "Option", "Some"),
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) )
+ ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, get_path(core_name, "option", "Option", "Some"),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) )
) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
@@ -709,10 +751,10 @@ class Deriver_PartialOrd:
)
);
}
- AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const
+ AST::ExprNodeP make_ret_equal(const RcString& core_name) const
{
- return NEWNODE(CallPath, this->get_path(core_name, "option", "Option", "Some"),
- ::make_vec1( NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal")) )
+ return NEWNODE(CallPath, get_path(core_name, "option", "Option", "Some"),
+ ::make_vec1( NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal")) )
);
}
public:
@@ -737,7 +779,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -771,45 +813,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b)))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t , auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b)));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b)))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](size_t /*idx*/, auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b)));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -833,54 +855,21 @@ public:
// TODO: Compare the discriminants using the `discriminant_value` intrinsic
// - Requires a way of emitting said intrinsic into the AST
- for(unsigned int a = 0; a < enm.variants().size(); a ++ )
+ // - LAZY WAY - hard-code ::"core"::intrinsics::discriminant_value
{
- for(unsigned int b = 0; b < enm.variants().size(); b ++ )
- {
- if( a == b )
- continue ;
-
- struct H {
- static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
- AST::Path var_path = base_path + v.m_name;
-
- TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
- (Value,
- return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
- ),
- (Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
- ),
- (Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
- )
- )
- throw "";
- }
- };
- ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
-
- ::std::vector< AST::Pattern> pats;
- {
- ::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
- }
-
- auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "option", "Option", "Some"),
- ::make_vec1(
- NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater")))
- )
- );
+ auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "PartialOrd", "partial_cmp"),
+ ::make_vec2(
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ),
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) )
+ )
+ );
+ ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() );
- arms.push_back(AST::ExprNode_Match_Arm(
- mv$(pats),
- nullptr,
- mv$(code)
- ));
- }
+ arms.push_back(AST::ExprNode_Match_Arm(
+ mv$(pats),
+ nullptr,
+ mv$(code)
+ ));
}
::std::vector<AST::ExprNodeP> vals;
@@ -896,11 +885,11 @@ public:
class Deriver_Eq:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Eq", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "cmp", "Eq");
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -918,7 +907,7 @@ class Deriver_Eq:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "assert_receiver_is_total_eq", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "assert_receiver_is_total_eq", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP assert_is_eq(const AST::Path& method_path, AST::ExprNodeP val) const {
@@ -928,6 +917,9 @@ class Deriver_Eq:
);
}
AST::ExprNodeP field(const ::std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
@@ -979,28 +971,18 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return this->assert_is_eq(assert_method_path, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return this->assert_is_eq(assert_method_path, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1041,19 +1023,10 @@ public:
class Deriver_Ord:
public Deriver
{
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) });
- }
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) });
- }
-
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ord", {}) });
- const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "Ord");
+ const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering");
AST::Function fcn(
sp,
@@ -1070,14 +1043,14 @@ class Deriver_Ord:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "cmp", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "cmp", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(Match,
- NEWNODE(CallPath, this->get_path(core_name, "cmp", "Ord", "cmp"),
+ NEWNODE(CallPath, get_path(core_name, "cmp", "Ord", "cmp"),
// TODO: Optional Ref?
::make_vec2(
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)),
@@ -1086,7 +1059,7 @@ class Deriver_Ord:
),
::make_vec2(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
),
@@ -1098,9 +1071,9 @@ class Deriver_Ord:
)
);
}
- AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const
+ AST::ExprNodeP make_ret_equal(const RcString& core_name) const
{
- return NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal"));
+ return NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal"));
}
public:
const char* trait_name() const override { return "Ord"; }
@@ -1124,7 +1097,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -1158,45 +1131,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t, auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& /*name*/, auto a, auto b) {
+ return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1218,50 +1171,21 @@ public:
));
}
- for(unsigned int a = 0; a < enm.variants().size(); a ++ )
- {
- for(unsigned int b = 0; b < enm.variants().size(); b ++ )
- {
- if( a == b )
- continue ;
-
- struct H {
- static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
- AST::Path var_path = base_path + v.m_name;
-
- TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
- (Value,
- return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
- ),
- (Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
- ),
- (Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
- )
- )
- throw "";
- }
- };
- ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
-
- ::std::vector< AST::Pattern> pats;
- {
- ::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
- }
- auto code = NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater")));
+ {
+ auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "Ord", "cmp"),
+ ::make_vec2(
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ),
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) )
+ )
+ );
+ ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() );
- arms.push_back(AST::ExprNode_Match_Arm(
- mv$(pats),
- nullptr,
- mv$(code)
- ));
- }
+ arms.push_back(AST::ExprNode_Match_Arm(
+ mv$(pats),
+ nullptr,
+ mv$(code)
+ ));
}
::std::vector<AST::ExprNodeP> vals;
@@ -1277,14 +1201,14 @@ public:
class Deriver_Clone:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
+ AST::Path get_trait_path(const RcString& core_name) const {
return AST::Path(core_name, { AST::PathNode("clone", {}), AST::PathNode("Clone", {}) });
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return get_trait_path(core_name) + "clone";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1302,25 +1226,28 @@ class Deriver_Clone:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "clone", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "clone", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP clone_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP clone_val_ref(const RcString& core_name, AST::ExprNodeP val) const {
// TODO: Hack for zero-sized arrays? (Not a 1.19 feature)
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val) ) )
);
}
- AST::ExprNodeP clone_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP clone_val_direct(const RcString& core_name, AST::ExprNodeP val) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( mv$(val) )
);
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(const ::std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
public:
const char* trait_name() const override { return "Clone"; }
@@ -1373,25 +1300,20 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) {
+ return this->clone_val_direct(opts.core_name, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
::AST::ExprNode_StructLiteral::t_values vals;
for( const auto& fld : e.m_fields )
{
- auto name_a = FMT("a" << fld.m_name);
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
vals.push_back({ {}, fld.m_name, this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) });
}
@@ -1436,7 +1358,7 @@ private:
for(auto& b : ret.def().params().bounds())
{
auto& be = b.as_IsTrait();
- be.trait = AST::Path(opts.core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) });
+ be.trait = get_path(opts.core_name, "marker", "Copy");
}
return ret;
@@ -1446,11 +1368,11 @@ private:
class Deriver_Copy:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "marker", "Copy");
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1481,14 +1403,14 @@ public:
class Deriver_Default:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("default", {}), AST::PathNode("Default", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "default", "Default");
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return AST::Path(AST::Path::TagUfcs(), ::TypeRef(Span()), get_trait_path(core_name), { AST::PathNode("default", {}) } );
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1504,10 +1426,10 @@ class Deriver_Default:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "default", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "default", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP default_call(const ::std::string& core_name) const {
+ AST::ExprNodeP default_call(const RcString& core_name) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
{}
@@ -1556,17 +1478,17 @@ public:
class Deriver_Hash:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hash", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "hash", "Hash");
}
- AST::Path get_trait_path_Hasher(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hasher", {}) });
+ AST::Path get_trait_path_Hasher(const RcString& core_name) const {
+ return get_path(core_name, "hash", "Hasher");
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return get_trait_path(core_name) + "hash";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1590,21 +1512,24 @@ class Deriver_Hash:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "hash", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "hash", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP hash_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP hash_val_ref(const RcString& core_name, AST::ExprNodeP val) const {
return this->hash_val_direct(core_name, NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) );
}
- AST::ExprNodeP hash_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP hash_val_direct(const RcString& core_name, AST::ExprNodeP val) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( mv$(val), NEWNODE(NamedValue, AST::Path("state")) )
);
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(const std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
public:
const char* trait_name() const override { return "Hash"; }
@@ -1654,30 +1579,20 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
- nodes.push_back( mv$(var_idx_hash) );
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) {
+ return this->hash_val_direct(opts.core_name, mv$(a));
+ });
+ nodes.insert(nodes.begin(), mv$(var_idx_hash));
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< AST::ExprNodeP > nodes;
- nodes.push_back( mv$(var_idx_hash) );
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t , auto a) {
+ return this->hash_val_direct(opts.core_name, mv$(a));
+ });
+ nodes.insert(nodes.begin(), mv$(var_idx_hash));
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1706,20 +1621,20 @@ class Deriver_RustcEncodable:
{
// NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names
AST::Path get_trait_path() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encodable", {}) });
+ return get_path("", "rustc_serialize", "Encodable");
}
AST::Path get_trait_path_Encoder() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encoder", {}) });
+ return get_path("", "rustc_serialize", "Encoder");
}
AST::Path get_method_path() const {
return get_trait_path() + "encode";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path();
- AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) });
+ AST::Path result_path = get_path(core_name, "result", "Result");
result_path.nodes()[1].args().m_types.push_back( TypeRef(TypeRef::TagUnit(), sp) );
result_path.nodes()[1].args().m_types.push_back(TypeRef( sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "S", 0x100|0), this->get_trait_path_Encoder(), { AST::PathNode("Error",{}) }) ));
@@ -1743,7 +1658,7 @@ class Deriver_RustcEncodable:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "encode", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "encode", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP enc_val_direct(AST::ExprNodeP val) const {
@@ -1752,9 +1667,12 @@ class Deriver_RustcEncodable:
AST::ExprNodeP enc_val_ref(AST::ExprNodeP val) const {
return this->enc_val_direct(NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) );
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(::std::string name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
AST::ExprNodeP enc_closure(Span sp, AST::ExprNodeP code) const {
return NEWNODE(Closure,
@@ -1762,8 +1680,8 @@ class Deriver_RustcEncodable:
mv$(code), false
);
}
- AST::ExprNodeP get_val_ok(const ::std::string& core_name) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( NEWNODE(Tuple, {})) );
+ AST::ExprNodeP get_val_ok(const RcString& core_name) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( NEWNODE(Tuple, {})) );
}
public:
@@ -1771,7 +1689,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
- const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str();
::std::vector<AST::ExprNodeP> nodes;
TU_MATCH(AST::StructData, (str.m_data), (e),
@@ -1783,7 +1701,12 @@ public:
{
nodes.push_back( NEWNODE(CallPath,
this->get_trait_path_Encoder() + "emit_struct_field",
- vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) ) )
+ vec$(
+ NEWNODE(NamedValue, AST::Path("s")),
+ NEWNODE(String, fld.m_name.c_str()),
+ NEWNODE(Integer, idx, CORETYPE_UINT),
+ this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) )
+ )
) );
idx ++;
}
@@ -1830,6 +1753,8 @@ public:
base_path.nodes().back().args() = ::AST::PathParams();
::std::vector<AST::ExprNode_Match_Arm> arms;
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+
for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++)
{
const auto& v = enm.variants()[var_idx];
@@ -1840,8 +1765,8 @@ public:
(Value,
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, 0, CORETYPE_UINT),
this->enc_closure(sp, this->get_val_ok(opts.core_name))
@@ -1851,26 +1776,21 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant_arg",
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_variant_arg"),
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
+ s_ent->clone(),
NEWNODE(Integer, idx, CORETYPE_UINT),
- this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a))))
+ this->enc_closure(sp, this->enc_val_direct(mv$(a)))
)
- ) );
- }
+ );
+ });
nodes.push_back( this->get_val_ok(opts.core_name) );
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, e.m_sub_types.size(), CORETYPE_UINT),
this->enc_closure(sp, NEWNODE(Block, mv$(nodes)))
@@ -1879,32 +1799,24 @@ public:
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< AST::ExprNodeP > nodes;
-
- unsigned int idx = 0;
- for( const auto& fld : e.m_fields )
- {
- auto name_a = Ident( FMT("a" << fld.m_name) );
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, Ident(name_a), ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant_field",
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_struct_variant_field"),
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, fld.m_name),
+ s_ent->clone(),
+ NEWNODE(String, e.m_fields[idx].m_name.c_str()),
NEWNODE(Integer, idx, CORETYPE_UINT),
- this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a.name))))
+ this->enc_closure(sp, this->enc_val_direct(mv$(a)))
)
- ) );
- idx ++;
- }
+ );
+ });
nodes.push_back( this->get_val_ok(opts.core_name) );
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, e.m_fields.size(), CORETYPE_UINT),
this->enc_closure(sp, NEWNODE(Block, mv$(nodes)))
@@ -1925,9 +1837,9 @@ public:
auto node_match = NEWNODE(Match, NEWNODE(NamedValue, AST::Path("self")), mv$(arms));
- const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str();
auto node = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum",
- vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) )
+ vec$( mv$(s_ent), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) )
);
return this->make_ret(sp, opts.core_name, p, type, this->get_field_bounds(enm), mv$(node));
@@ -1939,20 +1851,20 @@ class Deriver_RustcDecodable:
{
// NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names
AST::Path get_trait_path() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decodable", {}) });
+ return get_path("", "rustc_serialize", "Decodable");
}
AST::Path get_trait_path_Decoder() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decoder", {}) });
+ return get_path("", "rustc_serialize", "Decoder");
}
AST::Path get_method_path() const {
return get_trait_path() + "decode";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path();
- AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) });
+ AST::Path result_path = get_path(core_name, "result", "Result");
result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, "Self", 0xFFFF) );
result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "D", 0x100|0), this->get_trait_path_Decoder(), { AST::PathNode("Error",{}) })) );
@@ -1976,14 +1888,14 @@ class Deriver_RustcDecodable:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "decode", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "decode", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP dec_val() const {
return NEWNODE(CallPath, this->get_method_path(), vec$( NEWNODE(NamedValue, AST::Path("d")) ));
}
AST::ExprNodeP field(const ::std::string& name) const {
- return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path(RcString::new_interned("self"))), RcString::new_interned(name));
}
AST::ExprNodeP dec_closure(Span sp, AST::ExprNodeP code) const {
@@ -1992,8 +1904,8 @@ class Deriver_RustcDecodable:
mv$(code), false
);
}
- AST::ExprNodeP get_val_err_str(const ::std::string& core_name, ::std::string err_str) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Err",{})}), vec$(
+ AST::ExprNodeP get_val_err_str(const RcString& core_name, ::std::string err_str) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Err"), vec$(
NEWNODE(CallMethod,
NEWNODE(NamedValue, AST::Path("d")),
AST::PathNode("error"),
@@ -2001,10 +1913,10 @@ class Deriver_RustcDecodable:
)
) );
}
- AST::ExprNodeP get_val_ok(const ::std::string& core_name, AST::ExprNodeP inner) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( mv$(inner) ) );
+ AST::ExprNodeP get_val_ok(const RcString& core_name, AST::ExprNodeP inner) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( mv$(inner) ) );
}
- AST::ExprNodeP get_val_ok_unit(const ::std::string& core_name) const {
+ AST::ExprNodeP get_val_ok_unit(const RcString& core_name) const {
return get_val_ok(core_name, NEWNODE(Tuple, {}));
}
@@ -2014,7 +1926,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
AST::Path base_path = type.m_data.as_Path().path;
- const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str();
AST::ExprNodeP node_v;
TU_MATCH(AST::StructData, (str.m_data), (e),
@@ -2027,7 +1939,7 @@ public:
{
vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath,
this->get_trait_path_Decoder() + "read_struct_field",
- vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) )
+ vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) )
)) });
idx ++;
}
@@ -2094,7 +2006,6 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
- auto name_a = FMT("a" << idx);
args.push_back( NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant_arg",
vec$(
NEWNODE(NamedValue, AST::Path("d")),
@@ -2111,12 +2022,10 @@ public:
unsigned int idx = 0;
for( const auto& fld : e.m_fields )
{
- auto name_a = FMT("a" << fld.m_name);
-
vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_struct_variant_field",
vec$(
NEWNODE(NamedValue, AST::Path("d")),
- NEWNODE(String, fld.m_name),
+ NEWNODE(String, fld.m_name.c_str()),
NEWNODE(Integer, idx, CORETYPE_UINT),
this->dec_closure(sp, this->dec_val())
)
@@ -2136,7 +2045,7 @@ public:
nullptr,
this->get_val_ok(opts.core_name, mv$(code))
));
- var_name_strs.push_back( NEWNODE(String, v.m_name) );
+ var_name_strs.push_back( NEWNODE(String, v.m_name.c_str()) );
}
// Default arm
@@ -2158,7 +2067,7 @@ public:
mv$(node_match),
false
);
- const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str();
auto node_rev = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant",
vec$(
@@ -2180,7 +2089,7 @@ public:
// --------------------------------------------------------------------
// Select and dispatch the correct derive() handler
// --------------------------------------------------------------------
-static const Deriver* find_impl(const ::std::string& trait_name)
+static const Deriver* find_impl(const RcString& trait_name)
{
#define _(obj) if(trait_name == obj.trait_name()) return &obj;
_(g_derive_debug)
@@ -2199,7 +2108,7 @@ static const Deriver* find_impl(const ::std::string& trait_name)
}
template<typename T>
-static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::Attribute& attr, const AST::Path& path, const T& item)
+static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::Attribute& attr, const AST::Path& path, slice<const AST::Attribute> attrs, const T& item)
{
if( !attr.has_sub_items() ) {
//ERROR(sp, E0000, "#[derive()] requires a list of known traits to derive");
@@ -2221,13 +2130,13 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo
attr.items()
};
- ::std::vector< ::std::string> missing_handlers;
+ ::std::vector< RcString> missing_handlers;
for( const auto& trait : attr.items() )
{
DEBUG("- " << trait.name());
auto dp = find_impl(trait.name());
if( dp ) {
- mod.add_item(false, "", dp->handle_item(sp, opts, params, type, item), {} );
+ mod.add_item(sp, false, "", dp->handle_item(sp, opts, params, type, item), {} );
continue ;
}
@@ -2237,15 +2146,16 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo
bool found = false;
for(const auto& mac_path : mod.m_macro_imports)
{
- if( mac_path.first.back() == mac_name )
+ if( mac_path.name == mac_name )
{
- if( mac_path.second ) {
+ if( mac_path.macro_ptr ) {
// macro_rules! based derive?
TODO(sp, "Custom derive using macro_rules?");
}
else {
// proc_macro - Invoke the handler.
- auto lex = ProcMacro_Invoke(sp, crate, mac_path.first, path.nodes().back().name(), item);
+ DEBUG("proc_macro " << mac_path.path << ", attrs = " << attrs);
+ auto lex = ProcMacro_Invoke(sp, crate, mac_path.path, attrs, path.nodes().back().name().c_str(), item);
if( lex )
{
Parse_ModRoot_Items(*lex, mod);
@@ -2276,7 +2186,7 @@ class Decorator_Derive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
@@ -2286,13 +2196,13 @@ public:
// Ignore, it's been deleted
),
(Union,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
),
(Enum,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
),
(Struct,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
)
)
}
diff --git a/src/expand/env.cpp b/src/expand/env.cpp
index f4577ef1..825c895a 100644
--- a/src/expand/env.cpp
+++ b/src/expand/env.cpp
@@ -34,48 +34,44 @@ namespace {
class CExpanderEnv:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "env! doesn't take an ident");
::std::string varname = get_string(sp, crate, mod, tt);
const char* var_val_cstr = getenv(varname.c_str());
if( !var_val_cstr ) {
ERROR(sp, E0000, "Environment variable '" << varname << "' not defined");
}
- return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, var_val_cstr))) );
+ return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(var_val_cstr)))) );
}
};
class CExpanderOptionEnv:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "option_env! doesn't take an ident");
::std::string varname = get_string(sp, crate, mod, tt);
const char* var_val_cstr = getenv(varname.c_str());
if( !var_val_cstr ) {
::std::vector< TokenTree> rv;
rv.reserve(7);
- rv.push_back( Token(TOK_IDENT, "None") );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("None")) );
rv.push_back( Token(TOK_DOUBLE_COLON) );
rv.push_back( Token(TOK_LT) );
rv.push_back( Token(TOK_AMP) );
- rv.push_back( Token(TOK_LIFETIME, "static") );
- rv.push_back( Token(TOK_IDENT, "str") );
+ rv.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
rv.push_back( Token(TOK_GT) );
return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) );
}
else {
::std::vector< TokenTree> rv;
rv.reserve(4);
- rv.push_back( Token(TOK_IDENT, "Some") );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("Some")) );
rv.push_back( Token(TOK_PAREN_OPEN) );
- rv.push_back( Token(TOK_STRING, var_val_cstr) );
+ rv.push_back( Token(TOK_STRING, ::std::string(var_val_cstr)) );
rv.push_back( Token(TOK_PAREN_CLOSE) );
return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) );
}
diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp
index 7a827ccf..cfe859bd 100644
--- a/src/expand/file_line.cpp
+++ b/src/expand/file_line.cpp
@@ -8,6 +8,7 @@
#include <synext.hpp>
#include "../parse/common.hpp"
#include "../parse/ttstream.hpp"
+#include <ast/crate.hpp>
namespace {
const Span& get_top_span(const Span& sp) {
@@ -23,16 +24,16 @@ namespace {
class CExpanderFile:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, get_top_span(sp).filename.c_str()))) );
+ return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(get_top_span(sp).filename.c_str())))) );
}
};
class CExpanderLine:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_line, CORETYPE_U32))) );
}
@@ -41,7 +42,15 @@ class CExpanderLine:
class CExpanderColumn:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ 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 TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) );
}
@@ -50,13 +59,13 @@ class CExpanderColumn:
class CExpanderModulePath:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
::std::string path_str;
+ path_str += crate.m_crate_name;
for(const auto& comp : mod.path().nodes()) {
- if( &comp != &mod.path().nodes().front() )
- path_str += "::";
- path_str += comp.name();
+ path_str += "::";
+ path_str += comp.name().c_str();
}
return box$( TTStreamO(sp, TokenTree( Token(TOK_STRING, mv$(path_str)) )) );
}
@@ -65,5 +74,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/format_args.cpp b/src/expand/format_args.cpp
index 915af2af..7f33eb6d 100644
--- a/src/expand/format_args.cpp
+++ b/src/expand/format_args.cpp
@@ -34,7 +34,7 @@ namespace {
};
Align align = Align::Unspec;
- char align_char = ' ';
+ uint32_t align_char = ' ';
Sign sign = Sign::Unspec;
bool alternate = false;
@@ -118,17 +118,82 @@ namespace {
}
};
+ uint32_t parse_utf8(const char* s, int& out_len)
+ {
+ uint8_t v1 = s[0];
+ if( v1 < 0x80 )
+ {
+ out_len = 1;
+ return v1;
+ }
+ else if( (v1 & 0xC0) == 0x80 )
+ {
+ // Invalid (continuation)
+ out_len = 1;
+ return 0xFFFE;
+ }
+ else if( (v1 & 0xE0) == 0xC0 ) {
+ // Two bytes
+ out_len = 2;
+
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x1F) << 6)
+ | ((e1 & 0x3F) <<0)
+ ;
+ return outval;
+ }
+ else if( (v1 & 0xF0) == 0xE0 ) {
+ // Three bytes
+ out_len = 3;
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e2 = s[2];
+ if( (e2 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x0F) << 12)
+ | ((e1 & 0x3F) << 6)
+ | ((e2 & 0x3F) << 0)
+ ;
+ return outval;
+ }
+ else if( (v1 & 0xF8) == 0xF0 ) {
+ // Four bytes
+ out_len = 4;
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e2 = s[2];
+ if( (e2 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e3 = s[3];
+ if( (e3 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x07) << 18)
+ | ((e1 & 0x3F) << 12)
+ | ((e2 & 0x3F) << 6)
+ | ((e3 & 0x3F) << 0)
+ ;
+ return outval;
+ }
+ else {
+ throw ""; // Should be impossible.
+ }
+ }
+
/// Parse a format string into a sequence of fragments.
///
/// Returns a list of fragments, and the remaining free text after the last format sequence
::std::tuple< ::std::vector<FmtFrag>, ::std::string> parse_format_string(
const Span& sp,
const ::std::string& format_string,
- const ::std::map< ::std::string,unsigned int>& named,
+ const ::std::map<RcString,unsigned int>& named,
unsigned int n_free
)
{
- unsigned int n_named = named.size();
+ //unsigned int n_named = named.size();
unsigned int next_free = 0;
::std::vector<FmtFrag> frags;
@@ -183,7 +248,7 @@ namespace {
s ++;
} while(isdigit(*s));
if( arg_idx >= n_free )
- ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range");
+ ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range in \"" << format_string << "\"");
index = arg_idx;
}
else {
@@ -191,7 +256,7 @@ namespace {
while( isalnum(*s) || *s == '_' || (*s < 0 || *s > 127) ) {
s ++;
}
- ::std::string ident { start, s };
+ auto ident = RcString(start, s - start);
auto it = named.find(ident);
if( it == named.end() )
ERROR(sp, E0000, "Named argument '"<<ident<<"' not found");
@@ -209,9 +274,15 @@ namespace {
s ++; // eat ':'
// Alignment
- if( s[0] != '\0' && (s[1] == '<' || s[1] == '^' || s[1] == '>') ) {
- args.align_char = s[0];
- s ++;
+ // - Padding character, a single unicode codepoint followed by '<'/'^'/'>'
+ {
+ int next_c_i;
+ uint32_t ch = parse_utf8(s, next_c_i);
+ char next_c = s[next_c_i];
+ if( ch != '}' && ch != '\0' && (next_c == '<' || next_c == '^' || next_c == '>') ) {
+ args.align_char = ch;
+ s += next_c_i;
+ }
}
if( *s == '<' ) {
args.align = FmtArgs::Align::Left;
@@ -288,7 +359,7 @@ namespace {
}
if( *s == '$' )
{
- ::std::string ident { start, s };
+ auto ident = RcString(start, s - start);
auto it = named.find(ident);
if( it == named.end() )
ERROR(sp, E0000, "Named argument '"<<ident<<"' not found");
@@ -312,7 +383,7 @@ namespace {
if( next_free == n_free ) {
ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
}
- args.prec = next_free + n_named;
+ args.prec = next_free;
next_free ++;
}
else if( ::std::isdigit(*s) ) {
@@ -338,16 +409,17 @@ namespace {
}
}
+ if( s[0] == '\0' )
+ ERROR(sp, E0000, "Unexpected end of formatting string");
+
// Parse ident?
// - Lazy way is to just handle a single char and ensure that it is just a single char
- if( s[0] != '}' && s[0] != '\0' && s[1] != '}' ) {
- TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type)");
+ if( s[0] != '}' && s[1] != '}' ) {
+ TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type) - s=...\"" << s << "\"");
}
switch(s[0])
{
- case '\0':
- ERROR(sp, E0000, "Unexpected end of formatting string");
default:
ERROR(sp, E0000, "Unknown formatting type specifier '" << *s << "'");
case '}': trait_name = "Display"; break;
@@ -375,7 +447,7 @@ namespace {
if( next_free == n_free ) {
ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
}
- index = next_free + n_named;
+ index = next_free;
next_free ++;
}
@@ -392,6 +464,9 @@ namespace {
}
namespace {
+ Token ident(const char* s) {
+ return Token(TOK_IDENT, RcString::new_interned(s));
+ }
void push_path(::std::vector<TokenTree>& toks, const AST::Crate& crate, ::std::initializer_list<const char*> il)
{
switch(crate.m_load_std)
@@ -400,17 +475,17 @@ namespace {
break;
case ::AST::Crate::LOAD_CORE:
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, "core") );
+ toks.push_back( ident("core") );
break;
case ::AST::Crate::LOAD_STD:
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, "std") );
+ toks.push_back( ident("std") );
break;
}
for(auto ent : il)
{
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, ent) );
+ toks.push_back( ident(ent) );
}
}
void push_toks(::std::vector<TokenTree>& toks, Token t1) {
@@ -431,32 +506,23 @@ namespace {
toks.push_back( mv$(t3) );
toks.push_back( mv$(t4) );
}
-}
-class CFormatArgsExpander:
- 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
+ ::std::unique_ptr<TokenStream> expand_format_args(const Span& sp, const ::AST::Crate& crate, TTStream& lex, bool add_newline)
{
Token tok;
- auto lex = TTStream(sp, tt);
- lex.parse_state().module = &mod;
- if( ident != "" )
- ERROR(sp, E0000, "format_args! doesn't take an ident");
-
- auto n = Parse_ExprVal(lex);
- ASSERT_BUG(sp, n, "No expression returned");
- Expand_BareExpr(crate, mod, n);
+ auto format_string_node = Parse_ExprVal(lex);
+ ASSERT_BUG(sp, format_string_node, "No expression returned");
+ Expand_BareExpr(crate, lex.parse_state().get_current_mod(), format_string_node);
- auto* format_string_np = dynamic_cast<AST::ExprNode_String*>(&*n);
+ auto* format_string_np = dynamic_cast<AST::ExprNode_String*>(&*format_string_node);
if( !format_string_np ) {
- ERROR(sp, E0000, "format_args! requires a string literal - got " << *n);
+ ERROR(sp, E0000, "format_args! requires a string literal - got " << *format_string_node);
}
const auto& format_string_sp = format_string_np->span();
const auto& format_string = format_string_np->m_value;
- ::std::map< ::std::string, unsigned int> named_args_index;
+ ::std::map<RcString, unsigned int> named_args_index;
::std::vector<TokenTree> named_args;
::std::vector<TokenTree> free_args;
@@ -472,7 +538,7 @@ class CFormatArgsExpander:
if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_EQUAL )
{
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
@@ -497,6 +563,10 @@ class CFormatArgsExpander:
::std::vector< FmtFrag> fragments;
::std::string tail;
::std::tie( fragments, tail ) = parse_format_string(format_string_sp, format_string, named_args_index, free_args.size());
+ if( add_newline )
+ {
+ tail += "\n";
+ }
bool is_simple = true;
for(unsigned int i = 0; i < fragments.size(); i ++)
@@ -533,7 +603,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
for(unsigned int i = 0; i < free_args.size() + named_args.size(); i ++ )
{
- toks.push_back( Token(TOK_IDENT, FMT("a" << i)) );
+ toks.push_back( ident(FMT("a" << i).c_str()) );
toks.push_back( TokenTree(TOK_COMMA) );
}
toks.push_back( TokenTree(TOK_PAREN_CLOSE) );
@@ -545,13 +615,13 @@ class CFormatArgsExpander:
// - Contains N+1 entries, where N is the number of fragments
{
toks.push_back( TokenTree(TOK_RWORD_STATIC) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COLON) );
toks.push_back( TokenTree(TOK_SQUARE_OPEN) );
toks.push_back( Token(TOK_AMP) );
- toks.push_back( Token(TOK_LIFETIME, "static") );
- toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) );
+ toks.push_back( ident("str") );
toks.push_back( Token(TOK_SEMICOLON) );
toks.push_back( Token(static_cast<uint64_t>(fragments.size() + 1), CORETYPE_UINT) );
toks.push_back( TokenTree(TOK_SQUARE_CLOSE) );
@@ -577,7 +647,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
{
toks.push_back( TokenTree(TOK_AMP) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COMMA) );
toks.push_back( TokenTree(TOK_AMP) );
@@ -586,7 +656,7 @@ class CFormatArgsExpander:
{
push_path(toks, crate, {"fmt", "ArgumentV1", "new"});
toks.push_back( Token(TOK_PAREN_OPEN) );
- toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) );
+ toks.push_back( ident( FMT("a" << frag.arg_index).c_str() ) );
toks.push_back( TokenTree(TOK_COMMA) );
@@ -611,7 +681,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
{
toks.push_back( TokenTree(TOK_AMP) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COMMA) );
// TODO: Fragments to format
@@ -622,7 +692,7 @@ class CFormatArgsExpander:
{
push_path(toks, crate, {"fmt", "ArgumentV1", "new"});
toks.push_back( Token(TOK_PAREN_OPEN) );
- toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) );
+ toks.push_back( ident(FMT("a" << frag.arg_index).c_str()) );
toks.push_back( TokenTree(TOK_COMMA) );
@@ -640,17 +710,17 @@ class CFormatArgsExpander:
push_path(toks, crate, {"fmt", "rt", "v1", "Argument"});
toks.push_back( TokenTree(TOK_BRACE_OPEN) );
- push_toks(toks, Token(TOK_IDENT, "position"), TOK_COLON );
+ push_toks(toks, ident("position"), TOK_COLON );
push_path(toks, crate, {"fmt", "rt", "v1", "Position", "Next"});
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "format"), TOK_COLON );
+ push_toks(toks, ident("format"), TOK_COLON );
push_path(toks, crate, {"fmt", "rt", "v1", "FormatSpec"});
toks.push_back( TokenTree(TOK_BRACE_OPEN) );
{
- push_toks(toks, Token(TOK_IDENT, "fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA );
+ push_toks(toks, ident("fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA );
- push_toks(toks, Token(TOK_IDENT, "align"), TOK_COLON);
+ push_toks(toks, ident("align"), TOK_COLON);
const char* align_var_name = nullptr;
switch( frag.args.align )
{
@@ -662,19 +732,19 @@ class CFormatArgsExpander:
push_path(toks, crate, {"fmt", "rt", "v1", "Alignment", align_var_name});
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "flags"), TOK_COLON);
+ push_toks(toks, ident("flags"), TOK_COLON);
uint64_t flags = 0;
if(frag.args.alternate)
flags |= 1 << 2;
push_toks(toks, Token(uint64_t(flags), CORETYPE_U32));
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "precision"), TOK_COLON );
+ push_toks(toks, ident("precision"), TOK_COLON );
if( frag.args.prec_is_arg || frag.args.prec != 0 ) {
push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"});
push_toks(toks, TOK_PAREN_OPEN);
if( frag.args.prec_is_arg ) {
- push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.prec)) );
+ push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.prec).c_str()) );
}
else {
push_toks(toks, Token(uint64_t(frag.args.prec), CORETYPE_UINT) );
@@ -686,12 +756,12 @@ class CFormatArgsExpander:
}
toks.push_back( TokenTree(TOK_COMMA) );
- push_toks(toks, Token(TOK_IDENT, "width"), TOK_COLON );
+ push_toks(toks, ident("width"), TOK_COLON );
if( frag.args.width_is_arg || frag.args.width != 0 ) {
push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"});
push_toks(toks, TOK_PAREN_OPEN);
if( frag.args.width_is_arg ) {
- push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.width)) );
+ push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.width).c_str()) );
}
else {
push_toks(toks, Token(uint64_t(frag.args.width), CORETYPE_UINT) );
@@ -719,7 +789,36 @@ class CFormatArgsExpander:
return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) );
}
+}
+
+class CFormatArgsExpander:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ return expand_format_args(sp, crate, lex, /*add_newline=*/false);
+ }
+};
+
+class CFormatArgsNlExpander:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ return expand_format_args(sp, crate, lex, /*add_newline=*/true);
+ }
};
STATIC_MACRO("format_args", CFormatArgsExpander);
+STATIC_MACRO("format_args_nl", CFormatArgsNlExpander);
diff --git a/src/expand/include.cpp b/src/expand/include.cpp
index 59f33d47..14a7bc7b 100644
--- a/src/expand/include.cpp
+++ b/src/expand/include.cpp
@@ -12,6 +12,7 @@
#include <parse/ttstream.hpp>
#include <parse/lex.hpp> // Lexer (new files)
#include <ast/expr.hpp>
+#include <ast/crate.hpp>
namespace {
@@ -63,11 +64,8 @@ namespace {
class CIncludeExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -75,6 +73,7 @@ class CIncludeExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
try {
return box$( Lexer(file_path) );
@@ -89,11 +88,8 @@ class CIncludeExpander:
class CIncludeBytesExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include_bytes! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -101,6 +97,7 @@ class CIncludeBytesExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
::std::ifstream is(file_path);
if( !is.good() ) {
@@ -118,11 +115,8 @@ class CIncludeBytesExpander:
class CIncludeStrExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include_str! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -130,6 +124,7 @@ class CIncludeStrExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
::std::ifstream is(file_path);
if( !is.good() ) {
diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp
index 789ad88e..328bce9c 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( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } // In 1.29 this is Ord, before it was PartialOrd
+ 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); }
@@ -76,6 +78,8 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "debug_trait" ) { /* TODO: Poke derive() with this */ }
+ else if( TARGETVER_1_29 && name == "termination" ) { } // 1.29 - trait used for non-() main
+
// Structs
else if( name == "non_zero" ) { }
else if( name == "phantom_data" ) { }
@@ -84,18 +88,30 @@ 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" ) { }
+ // Extern functions
+ else if( name == "panic_impl" ) {
+ }
+ else if( name == "oom" ) {
+ }
+
// Functions
else if( name == "panic" ) { }
else if( name == "panic_bounds_check" ) { }
- else if( name == "panic_fmt" ) {
-
- }
+ else if( name == "panic_fmt" ) { }
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,11 +121,43 @@ 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 << "'");
}
+ if( type == AST::ITEM_EXTERN_FN )
+ {
+ // TODO: This should force a specific link name instead
+ return ;
+ }
+
auto rv = crate.m_lang_items.insert( ::std::make_pair( name, ::AST::Path(path) ) );
if( !rv.second ) {
const auto& other_path = rv.first->second;
@@ -125,7 +173,7 @@ class Decorator_LangItem:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
@@ -139,7 +187,7 @@ public:
handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_FN);
}
else {
- //handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_EXTERN_FN);
+ handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_EXTERN_FN);
}
),
(Static,
@@ -148,6 +196,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,9 +227,15 @@ public:
// collections
else if( name == "str" ) {}
else if( name == "slice" ) {}
+ else if( TARGETVER_1_29 && name == "slice_u8" ) {} // libcore now, `impl [u8]`
+ else if( TARGETVER_1_29 && name == "slice_alloc" ) {} // liballoc's impls on [T]
+ else if( TARGETVER_1_29 && name == "slice_u8_alloc" ) {} // liballoc's impls on [u8]
+ else if( TARGETVER_1_29 && name == "str_alloc" ) {} // liballoc's impls on str
// std - interestingly
else if( name == "f32" ) {}
else if( name == "f64" ) {}
+ else if( TARGETVER_1_29 && name == "f32_runtime" ) {}
+ else if( TARGETVER_1_29 && name == "f64_runtime" ) {}
else {
ERROR(sp, E0000, "Unknown lang item '" << name << "' on impl");
}
@@ -193,7 +250,7 @@ class Decorator_Main:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() ) {
// Ignore.
@@ -217,7 +274,7 @@ class Decorator_Start:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_IFLET(::AST::Item, i, Function, e,
auto rv = crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-start"), ::AST::Path(path) ));
@@ -233,9 +290,30 @@ public:
}
};
+class Decorator_PanicImplementation:
+ public ExpandDecorator
+{
+public:
+ AttrStage stage() const override { return AttrStage::Post; }
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
+ {
+ TU_IFLET(::AST::Item, i, Function, e,
+ auto rv = crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-panic_implementation"), ::AST::Path(path) ));
+ if( !rv.second )
+ {
+ const auto& other_path = rv.first->second;
+ ERROR(sp, E0000, "Duplicate definition of #[panic_implementation] - " << other_path << " and " << path);
+ }
+ )
+ else {
+ ERROR(sp, E0000, "#[panic_implementation] on non-function " << path);
+ }
+ }
+};
STATIC_DECORATOR("lang", Decorator_LangItem)
STATIC_DECORATOR("main", Decorator_Main);
STATIC_DECORATOR("start", Decorator_Start);
+STATIC_DECORATOR("panic_implementation", Decorator_PanicImplementation);
diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp
index 89f394e1..3b6e4efa 100644
--- a/src/expand/macro_rules.cpp
+++ b/src/expand/macro_rules.cpp
@@ -21,11 +21,12 @@
class CMacroRulesExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ ERROR(sp, E0000, "macro_rules! requires an identifier" );
+ }
+ ::std::unique_ptr<TokenStream> expand_ident(const Span& sp, const ::AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) override
{
- if( ident == "" )
- ERROR(sp, E0000, "macro_rules! requires an identifier" );
-
DEBUG("Parsing macro_rules! " << ident);
TTStream lex(sp, tt);
auto mac = Parse_MacroRules(lex);
@@ -40,7 +41,7 @@ class CMacroUseHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TRACE_FUNCTION_F("path=" << path);
@@ -48,7 +49,7 @@ class CMacroUseHandler:
// Just ignore
)
else TU_IFLET( ::AST::Item, i, Crate, ec_name,
- const auto& ec = crate.m_extern_crates.at(ec_name.name);
+ const auto& ec = crate.m_extern_crates.at(ec_name.name.c_str());
if( mi.has_sub_items() )
{
TODO(sp, "Named import from extern crate");
@@ -61,8 +62,13 @@ class CMacroUseHandler:
});
for(const auto& p : ec.m_hir->m_proc_macros)
{
- mod.m_macro_imports.push_back(::std::make_pair( p.path.m_components, nullptr ));
- mod.m_macro_imports.back().first.insert( mod.m_macro_imports.back().first.begin(), p.path.m_crate_name );
+ mod.m_macro_imports.push_back(AST::Module::MacroImport{ false, p.path.m_components.back(), p.path.m_components, nullptr });
+ mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.path.m_crate_name );
+ }
+ for(const auto& p : ec.m_hir->m_proc_macro_reexports)
+ {
+ mod.m_macro_imports.push_back(AST::Module::MacroImport{ /*is_pub=*/ false, p.first, p.second.path.m_components, nullptr });
+ mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.second.path.m_crate_name );
}
}
)
@@ -119,7 +125,7 @@ class CMacroExportHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() ) {
}
@@ -146,14 +152,14 @@ class CMacroReexportHandler:
public ExpandDecorator
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( !i.is_Crate() ) {
ERROR(sp, E0000, "Use of #[macro_reexport] on non-crate - " << i.tag_str());
}
const auto& crate_name = i.as_Crate().name;
- auto& ext_crate = *crate.m_extern_crates.at(crate_name).m_hir;
+ auto& ext_crate = *crate.m_extern_crates.at(crate_name.c_str()).m_hir;
if( mi.has_sub_items() )
{
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 5d6d3234..53358473 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
{
@@ -49,46 +55,67 @@ void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const
void Expand_Attr(const Span& sp, const ::AST::Attribute& a, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
+ bool found = false;
for( auto& d : g_decorators ) {
- if( d.first == a.name() ) {
+ if( a.name() == d.first ) {
DEBUG("#[" << d.first << "] " << (int)d.second->stage() << "-" << (int)stage);
if( d.second->stage() == stage ) {
f(sp, *d.second, a);
+ // TODO: Early return?
+ // TODO: Annotate the attribute as having been handled
}
+ found = true;
}
}
+ if( !found ) {
+ // TODO: Create no-op handlers for a whole heap of attributes
+ //WARNING(sp, W0000, "Unknown attribute " << a.name());
+ }
}
-void Expand_Attrs(/*const */::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
for( auto& a : attrs.m_items )
{
+ Expand_Attr(a.span(), a, stage, f);
+ }
+}
+void Expand_Attrs_CfgAttr(AST::AttributeList& attrs)
+{
+ for(auto it = attrs.m_items.begin(); it != attrs.m_items.end(); )
+ {
+ auto& a = *it;
if( a.name() == "cfg_attr" ) {
if( check_cfg(a.span(), a.items().at(0)) ) {
- // Wait? Why move?
auto inner_attr = mv$(a.items().at(1));
- Expand_Attr(inner_attr.span(), inner_attr, stage, f);
a = mv$(inner_attr);
+ ++ it;
}
else {
+ it = attrs.m_items.erase(it);
}
}
else {
- Expand_Attr(a.span(), a, stage, f);
+ ++ it;
}
}
}
-void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
{
- Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ if(!item.is_None()) d.handle(sp, a, crate, path, mod, item); });
+ Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){
+ if(!item.is_None()) {
+ // TODO: Pass attributes _after_ this attribute
+ d.handle(sp, a, crate, path, mod, slice<const AST::Attribute>(&a, &attrs.m_items.back() - &a + 1), item);
+ }
+ });
}
-void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
{
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
+ Span mi_span, const RcString& name, const RcString& input_ident, TokenTree& input_tt
)
{
if( name == "" ) {
@@ -99,7 +126,10 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c
{
if( name == m.first )
{
- auto e = m.second->expand(mi_span, crate, input_ident, input_tt, mod);
+ auto e = input_ident == ""
+ ? m.second->expand(mi_span, crate, input_tt, mod)
+ : m.second->expand_ident(mi_span, crate, input_ident, input_tt, mod)
+ ;
return e;
}
}
@@ -144,6 +174,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 RcString& name, const RcString& 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());
@@ -330,6 +371,10 @@ struct CExpandExpr:
LList<const AST::Module*> modstack;
::std::unique_ptr<::AST::ExprNode> replacement;
+ // Stack of `try { ... }` blocks (the string is the loop label for the desugaring)
+ ::std::vector<RcString> m_try_stack;
+ unsigned m_try_index = 0;
+
AST::ExprNode_Block* current_block = nullptr;
CExpandExpr(::AST::Crate& crate, LList<const AST::Module*> ms):
@@ -346,6 +391,7 @@ struct CExpandExpr:
if(cnode.get())
{
auto attrs = mv$(cnode->attrs());
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, cnode); });
if(cnode.get())
cnode->attrs() = mv$(attrs);
@@ -494,6 +540,7 @@ struct CExpandExpr:
if( auto* node_mac = dynamic_cast<::AST::ExprNode_Macro*>(it->get()) )
{
+ Expand_Attrs_CfgAttr( (*it)->attrs() );
Expand_Attrs((*it)->attrs(), AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, *it); });
if( !it->get() ) {
it = node.m_nodes.erase( it );
@@ -530,6 +577,25 @@ struct CExpandExpr:
this->modstack = mv$(prev_modstack);
}
+ void visit(::AST::ExprNode_Try& node) override {
+ // Desugar into
+ // ```
+ // loop '#tryNNN {
+ // break '#tryNNN { ... }
+ // }
+ // ```
+ // NOTE: MIR lowering and HIR typecheck need to know to skip these (OR resolve should handle naming all loop blocks)
+ m_try_stack.push_back(RcString::new_interned(FMT("#try" << m_try_index++)));
+ this->visit_nodelete(node, node.m_inner);
+ auto loop_name = mv$(m_try_stack.back());
+ m_try_stack.pop_back();
+
+ auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core");
+ auto path_Ok = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Ok")});
+ auto ok_node = ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( mv$(path_Ok), ::make_vec1(mv$(node.m_inner)) ));
+ auto break_node = AST::ExprNodeP(new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, loop_name, mv$(ok_node)));
+ this->replacement = AST::ExprNodeP(new AST::ExprNode_Loop(loop_name, mv$(break_node)));
+ }
void visit(::AST::ExprNode_Asm& node) override {
for(auto& v : node.m_output)
this->visit_nodelete(node, v.value);
@@ -627,6 +693,7 @@ struct CExpandExpr:
this->visit_nodelete(node, node.m_val);
for(auto& arm : node.m_arms)
{
+ Expand_Attrs_CfgAttr( arm.m_attrs );
Expand_Attrs(arm.m_attrs, AttrStage::Pre , [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, arm); });
if( arm.m_patterns.size() == 0 )
continue ;
@@ -673,6 +740,7 @@ struct CExpandExpr:
this->visit_nodelete(node, node.m_base_value);
for(auto& val : node.m_values)
{
+ Expand_Attrs_CfgAttr(val.attrs);
Expand_Attrs(val.attrs, AttrStage::Pre , [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, val); });
if( !val.value )
continue ;
@@ -755,6 +823,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 +832,8 @@ struct CExpandExpr:
::AST::ExprNode_StructLiteral::t_values values;
values.push_back({ {}, "start", mv$(node.m_left) });
values.push_back({ {}, "end" , mv$(node.m_right) });
+ if( TARGETVER_1_29 )
+ 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 +857,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,15 +880,15 @@ 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,
::AST::ExprNodeP(new ::AST::ExprNode_Flow(
- ::AST::ExprNode_Flow::RETURN,
- "",
+ (m_try_stack.empty() ? ::AST::ExprNode_Flow::RETURN : ::AST::ExprNode_Flow::BREAK), // NOTE: uses `break 'tryblock` instead of return if in a try block.
+ (m_try_stack.empty() ? RcString("") : m_try_stack.back()),
::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 +899,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)
+ ));
}
}
};
@@ -895,6 +979,7 @@ void Expand_BareExpr(const ::AST::Crate& crate, const AST::Module& mod, ::std::u
void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, ::AST::Impl& impl)
{
TRACE_FUNCTION_F(impl.def());
+ Expand_Attrs_CfgAttr(impl.def().attrs());
Expand_Attrs(impl.def().attrs(), AttrStage::Pre, crate, mod, impl.def());
if( impl.def().type().is_wildcard() ) {
DEBUG("Deleted");
@@ -909,18 +994,19 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
for( unsigned int idx = 0; idx < impl.items().size(); idx ++ )
{
auto& i = impl.items()[idx];
- DEBUG(" - " << i.name << " :: " << i.data->attrs);
+ DEBUG(" - " << i.name << " :: " << i.attrs);
// TODO: Make a path from the impl definition? Requires having the impl def resolved to be correct
// - Does it? the namespace is essentially the same. There may be issues with wherever the path is used though
//::AST::Path path = modpath + i.name;
- auto attrs = mv$(i.data->attrs);
+ auto attrs = mv$(i.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, *i.data);
TU_MATCH_DEF(AST::Item, (*i.data), (e),
(
- throw ::std::runtime_error("BUG: Unknown item type in impl block");
+ BUG(Span(), "Unknown item type in impl block - " << i.data->tag_str());
),
(None, ),
(MacroInv,
@@ -970,8 +1056,8 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
auto& i = impl.items()[idx];
Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, *i.data);
// TODO: How would this be populated? It got moved out?
- if( i.data->attrs.m_items.size() == 0 )
- i.data->attrs = mv$(attrs);
+ if( i.attrs.m_items.size() == 0 )
+ i.attrs = mv$(attrs);
}
}
@@ -979,6 +1065,7 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
}
void Expand_ImplDef(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, ::AST::ImplDef& impl_def)
{
+ Expand_Attrs_CfgAttr(impl_def.attrs());
Expand_Attrs(impl_def.attrs(), AttrStage::Pre, crate, mod, impl_def);
if( impl_def.type().is_wildcard() ) {
DEBUG("Deleted");
@@ -1011,14 +1098,14 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
}
for( const auto& mi: mod.m_macro_imports )
- DEBUG("- Imports '" << mi.first << "'");
+ DEBUG("- Imports '" << mi.path << "'");
}
// Insert prelude if: Enabled for this module, present for the crate, and this module is not an anon
if( crate.m_prelude_path != AST::Path() )
{
if( mod.m_insert_prelude && ! mod.is_anon() ) {
- mod.add_alias(false, ::AST::UseStmt(Span(), crate.m_prelude_path), "", {});
+ mod.add_item(Span(), false, "", ::AST::UseItem { Span(), ::make_vec1(::AST::UseItem::Ent { Span(), crate.m_prelude_path, "" }) }, {});
}
}
@@ -1027,19 +1114,20 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
{
auto& i = mod.items()[idx];
- DEBUG("- " << modpath << "::" << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.data.attrs);
+ DEBUG("- " << modpath << "::" << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.attrs);
::AST::Path path = modpath + i.name;
- auto attrs = mv$(i.data.attrs);
+ auto attrs = mv$(i.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, path, mod, i.data);
auto dat = mv$(i.data);
- TU_MATCH(::AST::Item, (dat), (e),
- (None,
- // Skip, nothing
- ),
- (MacroInv,
+ TU_MATCH_HDRA( (dat), {)
+ TU_ARMA(None, e) {
+ // Skip: nothing
+ }
+ TU_ARMA(MacroInv, e) {
// Move out of the module to avoid invalidation if a new macro invocation is added
auto mi_owned = mv$(e);
@@ -1056,11 +1144,14 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
Parse_ModRoot_Items(*ttl, mod);
}
dat.as_MacroInv() = mv$(mi_owned);
- ),
- (Use,
+ }
+ TU_ARMA(Macro, e) {
+ mod.add_macro(i.is_pub, i.name, mv$(e));
+ }
+ TU_ARMA(Use, e) {
// No inner expand.
- ),
- (ExternBlock,
+ }
+ TU_ARMA(ExternBlock, e) {
// TODO: Run expand on inner items?
// HACK: Just convert inner items into outer items
auto items = mv$( e.items() );
@@ -1068,32 +1159,32 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
{
mod.items().push_back( mv$(i2) );
}
- ),
- (Impl,
+ }
+ TU_ARMA(Impl, e) {
Expand_Impl(crate, modstack, modpath, mod, e);
if( e.def().type().is_wildcard() ) {
dat = AST::Item();
}
- ),
- (NegImpl,
+ }
+ TU_ARMA(NegImpl, e) {
Expand_ImplDef(crate, modstack, modpath, mod, e);
if( e.type().is_wildcard() ) {
dat = AST::Item();
}
- ),
- (Module,
+ }
+ TU_ARMA(Module, e) {
LList<const AST::Module*> sub_modstack(&modstack, &e);
Expand_Mod(crate, sub_modstack, path, e);
- ),
- (Crate,
+ }
+ TU_ARMA(Crate, e) {
// Can't recurse into an `extern crate`
if(crate.m_extern_crates.count(e.name) == 0)
{
- e.name = crate.load_extern_crate( i.data.span, e.name );
+ e.name = crate.load_extern_crate( i.span, e.name );
+ }
}
- ),
- (Struct,
+ TU_ARMA(Struct, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
TU_MATCH(AST::StructData, (e.m_data), (sd),
(Unit,
@@ -1101,6 +1192,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Struct,
for(auto it = sd.ents.begin(); it != sd.ents.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1114,6 +1206,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Tuple,
for(auto it = sd.ents.begin(); it != sd.ents.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1125,10 +1218,11 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
)
)
- ),
- (Enum,
+ }
+ TU_ARMA(Enum, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& var : e.variants()) {
+ Expand_Attrs_CfgAttr(var.m_attrs);
Expand_Attrs(var.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); });
TU_MATCH(::AST::EnumVariantData, (var.m_data), (e),
(Value,
@@ -1142,6 +1236,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Struct,
for(auto it = e.m_fields.begin(); it != e.m_fields.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1155,11 +1250,22 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
)
Expand_Attrs(var.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); });
}
- ),
- (Union,
+ // Handle cfg on variants (kinda hacky)
+ for(auto it = e.variants().begin(); it != e.variants().end(); ) {
+ if( it->m_name == "" ) {
+ it = e.variants().erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ }
+ TU_ARMA(Union, e) {
Expand_GenericParams(crate, modstack, mod, e.m_params);
- for(auto it = e.m_variants.begin(); it != e.m_variants.end(); ) {
+ for(auto it = e.m_variants.begin(); it != e.m_variants.end(); )
+ {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1169,20 +1275,48 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
else
++it;
}
- ),
- (Trait,
+ }
+ TU_ARMA(Trait, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
- for(auto& ti : e.items())
+ auto& trait_items = e.items();
+ for(size_t idx = 0; idx < trait_items.size(); idx ++)
{
+ auto& ti = trait_items[idx];
DEBUG(" - " << ti.name << " " << ti.data.tag_str());
- auto attrs = mv$(ti.data.attrs);
+ auto attrs = mv$(ti.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, ti.data);
TU_MATCH_DEF(AST::Item, (ti.data), (e),
(
- throw ::std::runtime_error("BUG: Unknown item type in impl block");
+ BUG(Span(), "Unknown item type in trait block - " << ti.data.tag_str());
),
(None, ),
+ (MacroInv,
+ if( e.name() != "" )
+ {
+ TRACE_FUNCTION_F("Macro invoke " << e.name());
+ // Move out of the module to avoid invalidation if a new macro invocation is added
+ auto mi_owned = mv$(e);
+
+ auto ttl = Expand_Macro(crate, modstack, mod, mi_owned);
+
+ if( ttl.get() )
+ {
+ // Re-parse tt
+ size_t insert_pos = idx+1;
+ while( ttl->lookahead(0) != TOK_EOF )
+ {
+ auto i = Parse_Trait_Item(*ttl);
+ trait_items.insert( trait_items.begin() + insert_pos, mv$(i) );
+ insert_pos ++;
+ }
+ // - Any new macro invocations ends up at the end of the list and handled
+ }
+ // Move back in (using the index, as the old pointer may be invalid)
+ trait_items[idx].data.as_MacroInv() = mv$(mi_owned);
+ }
+ ),
(Function,
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& arg : e.args()) {
@@ -1201,16 +1335,20 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
)
)
- Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data);
- if( ti.data.attrs.m_items.size() == 0 )
- ti.data.attrs = mv$(attrs);
+ {
+ auto& ti = trait_items[idx];
+
+ Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data);
+ if( ti.attrs.m_items.size() == 0 )
+ ti.attrs = mv$(attrs);
+ }
}
- ),
- (Type,
+ }
+ TU_ARMA(Type, e) {
Expand_Type(crate, modstack, mod, e.type());
- ),
+ }
- (Function,
+ TU_ARMA(Function, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& arg : e.args()) {
Expand_Pattern(crate, modstack, mod, arg.first, false);
@@ -1218,12 +1356,12 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
Expand_Type(crate, modstack, mod, e.rettype());
Expand_Expr(crate, modstack, e.code());
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
Expand_Expr(crate, modstack, e.value());
Expand_Type(crate, modstack, mod, e.type());
- )
- )
+ }
+ }
Expand_Attrs(attrs, AttrStage::Post, crate, path, mod, dat);
{
@@ -1233,8 +1371,8 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
i.data = mv$(dat);
}
// TODO: When would this _not_ be empty?
- if( i.data.attrs.m_items.size() == 0 )
- i.data.attrs = mv$(attrs);
+ if( i.attrs.m_items.size() == 0 )
+ i.attrs = mv$(attrs);
}
}
@@ -1285,6 +1423,7 @@ void Expand(::AST::Crate& crate)
auto modstack = LList<const ::AST::Module*>(nullptr, &crate.m_root_module);
// 1. Crate attributes
+ Expand_Attrs_CfgAttr(crate.m_attrs);
Expand_Attrs(crate.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate); });
// Insert magic for libstd/libcore
@@ -1297,7 +1436,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("std").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "std", "std", ::AST::AttributeList {});
+ crate.m_root_module.add_ext_crate(Span(), /*is_pub=*/false, "std", "std", /*attrs=*/{});
break;
case ::AST::Crate::LOAD_CORE:
if( crate.m_prelude_path == AST::Path() )
@@ -1305,7 +1444,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("core").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "core", "core", ::AST::AttributeList {});
+ crate.m_root_module.add_ext_crate(Span(), /*is_pub=*/false, "core", "core", /*attrs=*/{});
break;
case ::AST::Crate::LOAD_NONE:
break;
@@ -1315,7 +1454,7 @@ void Expand(::AST::Crate& crate)
for( auto& a : crate.m_attrs.m_items )
{
for( auto& d : g_decorators ) {
- if( d.first == a.name() && d.second->stage() == AttrStage::Pre ) {
+ if( a.name() == d.first && d.second->stage() == AttrStage::Pre ) {
//d.second->handle(a, crate, ::AST::Path(), crate.m_root_module, crate.m_root_module);
}
}
@@ -1324,6 +1463,8 @@ void Expand(::AST::Crate& crate)
// 3. Module tree
Expand_Mod(crate, modstack, ::AST::Path("",{}), crate.m_root_module);
+ //Expand_Attrs(crate.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate); });
+
// Post-process
Expand_Mod_IndexAnon(crate, crate.m_root_module);
}
diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp
index b61851b3..bc882d77 100644
--- a/src/expand/proc_macro.cpp
+++ b/src/expand/proc_macro.cpp
@@ -35,7 +35,7 @@ class Decorator_ProcMacroDerive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() )
return;
@@ -49,13 +49,13 @@ public:
{
if( attr.items()[i].name() == "attributes") {
for(const auto& si : attr.items()[i].items()) {
- attributes.push_back( si.name() );
+ attributes.push_back( si.name().c_str() );
}
}
}
// TODO: Store attributes for later use.
- crate.m_proc_macros.push_back(AST::ProcMacroDef { FMT("derive#" << trait_name), path, mv$(attributes) });
+ crate.m_proc_macros.push_back(AST::ProcMacroDef { RcString::new_interned(FMT("derive#" << trait_name)), path, mv$(attributes) });
}
};
@@ -100,7 +100,7 @@ void Expand_ProcMacro(::AST::Crate& crate)
{
::AST::ExprNode_StructLiteral::t_values desc_vals;
// `name: "foo",`
- desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name) });
+ desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name.c_str()) });
// `handler`: ::foo
desc_vals.push_back({ {}, "handler", NEWNODE(_NamedValue, AST::Path(desc.path)) });
@@ -121,12 +121,12 @@ void Expand_ProcMacro(::AST::Crate& crate)
auto newmod = ::AST::Module { ::AST::Path("", { ::AST::PathNode("proc_macro#") }) };
// - TODO: These need to be loaded too.
// > They don't actually need to exist here, just be loaded (and use absolute paths)
- newmod.add_ext_crate(false, "proc_macro", "proc_macro", {});
+ newmod.add_ext_crate(Span(), false, "proc_macro", "proc_macro", {});
- newmod.add_item(false, "main", mv$(main_fn), {});
- newmod.add_item(false, "MACROS", mv$(tests_list), {});
+ newmod.add_item(Span(), false, "main", mv$(main_fn), {});
+ newmod.add_item(Span(), false, "MACROS", mv$(tests_list), {});
- crate.m_root_module.add_item(false, "proc_macro#", mv$(newmod), {});
+ crate.m_root_module.add_item(Span(), false, "proc_macro#", mv$(newmod), {});
crate.m_lang_items["mrustc-main"] = ::AST::Path("", { AST::PathNode("proc_macro#"), AST::PathNode("main") });
}
@@ -211,7 +211,7 @@ public:
void send_float(eCoreType ct, double v);
//void send_fragment();
- bool attr_is_used(const ::std::string& n) const {
+ bool attr_is_used(const RcString& n) const {
return ::std::find(m_proc_macro_desc.attributes.begin(), m_proc_macro_desc.attributes.end(), n) != m_proc_macro_desc.attributes.end();
}
@@ -229,8 +229,9 @@ private:
uint64_t recv_v128u();
};
-ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path)
+ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path)
{
+ TRACE_FUNCTION_F(mac_path);
// 1. Locate macro in HIR list
const auto& crate_name = mac_path.front();
const auto& ext_crate = crate.m_extern_crates.at(crate_name);
@@ -259,7 +260,8 @@ ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, con
}
// 2. Get executable and macro name
- ::std::string proc_macro_exe_name = (ext_crate.m_filename + "-plugin");
+ // TODO: Windows will have .exe?
+ ::std::string proc_macro_exe_name = ext_crate.m_filename;
// 3. Create ProcMacroInv
return ProcMacroInv(sp, proc_macro_exe_name.c_str(), *pmp);
@@ -516,6 +518,9 @@ namespace {
TODO(sp, "");
m_pmi.send_symbol("}");
}
+ void visit(::AST::ExprNode_Try& node) {
+ TODO(sp, "ExprNode_Try");
+ }
void visit(::AST::ExprNode_Macro& node) {
TODO(sp, "ExprNode_Macro");
}
@@ -606,12 +611,27 @@ namespace {
TODO(sp, "ExprNode_UniOp");
}
+ void visit_top_attrs(slice<const ::AST::Attribute>& attrs)
+ {
+ for(const auto& a : attrs)
+ {
+ if( m_pmi.attr_is_used(a.name()) )
+ {
+ DEBUG("Send " << a);
+ m_pmi.send_symbol("#");
+ m_pmi.send_symbol("[");
+ this->visit_meta_item(a);
+ m_pmi.send_symbol("]");
+ }
+ }
+ }
void visit_attrs(const ::AST::AttributeList& attrs)
{
for(const auto& a : attrs.m_items)
{
if( m_pmi.attr_is_used(a.name()) )
{
+ DEBUG("Send " << a);
m_pmi.send_symbol("#");
m_pmi.send_symbol("[");
this->visit_meta_item(a);
@@ -704,12 +724,15 @@ namespace {
{
this->visit_attrs(v.m_attrs);
m_pmi.send_ident(v.m_name.c_str());
- TU_MATCH(AST::EnumVariantData, (v.m_data), (e),
- (Value,
- m_pmi.send_symbol("=");
- this->visit_nodes(e.m_value);
- ),
- (Tuple,
+ TU_MATCH_HDRA( (v.m_data), { )
+ TU_ARMA(Value, e) {
+ if( e.m_value )
+ {
+ m_pmi.send_symbol("=");
+ this->visit_nodes(e.m_value);
+ }
+ }
+ TU_ARMA(Tuple, e) {
m_pmi.send_symbol("(");
for(const auto& st : e.m_sub_types)
{
@@ -718,8 +741,8 @@ namespace {
m_pmi.send_symbol(",");
}
m_pmi.send_symbol(")");
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
m_pmi.send_symbol("{");
for(const auto& f : e.m_fields)
{
@@ -730,8 +753,8 @@ namespace {
m_pmi.send_symbol(",");
}
m_pmi.send_symbol("}");
- )
- )
+ }
+ }
m_pmi.send_symbol(",");
}
m_pmi.send_symbol("}");
@@ -742,38 +765,45 @@ namespace {
}
};
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Struct& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Struct& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_struct(item_name, false, i);
+ // TODO: Get attributes from the caller, filter based on the macro's options then pass to the child.
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_struct(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Enum& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Enum& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_enum(item_name, false, i);
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_enum(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Union& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Union& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_union(item_name, false, i);
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_union(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
@@ -813,11 +843,12 @@ ProcMacroInv::ProcMacroInv(const Span& sp, const char* executable, const ::HIR::
posix_spawn_file_actions_addclose(&file_actions, stdout_pipes[1]);
char* argv[3] = { const_cast<char*>(executable), const_cast<char*>(proc_macro_desc.name.c_str()), nullptr };
+ DEBUG(argv[0] << " " << argv[1]);
//char* envp[] = { nullptr };
int rv = posix_spawn(&this->child_pid, executable, &file_actions, nullptr, argv, environ);
if( rv != 0 )
{
- BUG(sp, "Error in posix_spawn - " << rv);
+ BUG(sp, "Error in posix_spawn - " << rv << " - can't start `" << executable << "`");
}
posix_spawn_file_actions_destroy(&file_actions);
@@ -1015,11 +1046,11 @@ Token ProcMacroInv::realGetToken_() {
auto t = Lex_FindReservedWord(val);
if( t != TOK_NULL )
return t;
- return Token(TOK_IDENT, mv$(val));
+ return Token(TOK_IDENT, RcString::new_interned(val));
}
case TokenClass::Lifetime: {
auto val = this->recv_bytes();
- return Token(TOK_LIFETIME, mv$(val));
+ return Token(TOK_LIFETIME, RcString::new_interned(val));
}
case TokenClass::String: {
auto val = this->recv_bytes();
diff --git a/src/expand/proc_macro.hpp b/src/expand/proc_macro.hpp
index 8c5b71c7..a4a190e8 100644
--- a/src/expand/proc_macro.hpp
+++ b/src/expand/proc_macro.hpp
@@ -8,8 +8,8 @@
#pragma once
#include <parse/tokenstream.hpp>
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Struct& i);
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Enum& i);
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Union& i);
-//extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const TokenStream& tt);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Struct& i);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Enum& i);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Union& i);
+//extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, const TokenStream& tt);
diff --git a/src/expand/rustc_diagnostics.cpp b/src/expand/rustc_diagnostics.cpp
index 0e95bb7c..b36bf586 100644
--- a/src/expand/rustc_diagnostics.cpp
+++ b/src/expand/rustc_diagnostics.cpp
@@ -13,7 +13,7 @@
class CExpanderRegisterDiagnostic:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree()) );
}
@@ -21,7 +21,7 @@ class CExpanderRegisterDiagnostic:
class CExpanderDiagnosticUsed:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree()) );
}
@@ -29,10 +29,8 @@ class CExpanderDiagnosticUsed:
class CExpanderBuildDiagnosticArray:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "__build_diagnostic_array! doesn't take an ident");
auto lex = TTStream(sp, tt);
Token tok;
@@ -41,7 +39,7 @@ class CExpanderBuildDiagnosticArray:
//auto crate_name = mv$(tok.str());
GET_CHECK_TOK(tok, lex, TOK_COMMA);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto item_name = mv$(tok.str());
+ auto item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::vector<TokenTree> toks;
@@ -51,9 +49,9 @@ class CExpanderBuildDiagnosticArray:
toks.push_back( TOK_COLON );
toks.push_back( TOK_SQUARE_OPEN );
toks.push_back( TOK_PAREN_OPEN );
- toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
toks.push_back( TOK_COMMA );
- toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
toks.push_back( TOK_PAREN_CLOSE );
toks.push_back( TOK_SEMICOLON );
toks.push_back( Token(static_cast<uint64_t>(0), CORETYPE_UINT) );
diff --git a/src/expand/std_prelude.cpp b/src/expand/std_prelude.cpp
index d6022959..58b56cf7 100644
--- a/src/expand/std_prelude.cpp
+++ b/src/expand/std_prelude.cpp
@@ -47,7 +47,7 @@ class Decorator_NoPrelude:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( i.is_Module() ) {
i.as_Module().m_insert_prelude = false;
}
@@ -63,14 +63,14 @@ class Decorator_PreludeImport:
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( i.is_Use() ) {
- const auto& p = i.as_Use().path;
+ const auto& p = i.as_Use().entries.front().path;
// TODO: Ensure that this statement is a glob (has a name of "")
crate.m_prelude_path = AST::Path(p);
}
else {
- ERROR(sp, E0000, "Invalid use of #[no_prelude] on non-module");
+ ERROR(sp, E0000, "Invalid use of #[prelude_import] on non-module");
}
}
};
diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp
index 06c65c02..561177ef 100644
--- a/src/expand/stringify.cpp
+++ b/src/expand/stringify.cpp
@@ -12,7 +12,7 @@
class CExpander:
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
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
::std::string rv;
@@ -22,9 +22,13 @@ class CExpander:
{
if(!rv.empty())
rv += " ";
+ DEBUG(" += " << tok);
rv += tok.to_str();
}
+ // TODO: Strip out any `{...}` sequences that aren't from nested
+ // strings.
+
return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, mv$(rv)))) );
}
};
diff --git a/src/expand/test.cpp b/src/expand/test.cpp
index 9497c692..eec1414d 100644
--- a/src/expand/test.cpp
+++ b/src/expand/test.cpp
@@ -14,7 +14,7 @@ class CTestHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[test] can only be put on functions - found on " << i.tag_str());
}
@@ -25,7 +25,7 @@ class CTestHandler:
for(const auto& node : path.nodes())
{
td.name += "::";
- td.name += node.name();
+ td.name += node.name().c_str();
}
td.path = ::AST::Path(path);
@@ -40,15 +40,16 @@ class CTestHandler:
class CTestHandler_SP:
public ExpandDecorator
{
- AttrStage stage() const override { return AttrStage::Pre; }
+ AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
}
if( crate.m_test_harness )
{
+ // TODO: If this test doesn't yet exist, create it (but as disabled)?
for(auto& td : crate.m_tests)
{
if( td.path != path )
@@ -73,11 +74,11 @@ class CTestHandler_SP:
class CTestHandler_Ignore:
public ExpandDecorator
{
- AttrStage stage() const override { return AttrStage::Pre; }
+ AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
- ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
+ ERROR(sp, E0000, "#[ignore] can only be put on functions - found on " << i.tag_str());
}
if( crate.m_test_harness )
diff --git a/src/expand/test_harness.cpp b/src/expand/test_harness.cpp
index 204ca75e..456f90e4 100644
--- a/src/expand/test_harness.cpp
+++ b/src/expand/test_harness.cpp
@@ -81,13 +81,18 @@ void Expand_TestHarness(::AST::Crate& crate)
}
desc_vals.push_back({ {}, "should_panic", mv$(should_panic_val) });
}
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Get this from attributes
+ desc_vals.push_back({ {}, "allow_fail", NEWNODE(_Bool, false) });
+ }
auto desc_expr = NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDesc")}), nullptr, mv$(desc_vals));
::AST::ExprNode_StructLiteral::t_values descandfn_vals;
- descandfn_vals.push_back({ {}, ::std::string("desc"), mv$(desc_expr) });
+ descandfn_vals.push_back({ {}, RcString::new_interned("desc"), mv$(desc_expr) });
auto test_type_var_name = test.is_benchmark ? "StaticBenchFn" : "StaticTestFn";
- descandfn_vals.push_back({ {}, ::std::string("testfn"), NEWNODE(_CallPath,
+ descandfn_vals.push_back({ {}, RcString::new_interned("testfn"), NEWNODE(_CallPath,
::AST::Path("test", { ::AST::PathNode(test_type_var_name) }),
::make_vec1( NEWNODE(_NamedValue, AST::Path(test.path)) )
) });
@@ -109,12 +114,12 @@ void Expand_TestHarness(::AST::Crate& crate)
auto newmod = ::AST::Module { ::AST::Path("", { ::AST::PathNode("test#") }) };
// - TODO: These need to be loaded too.
// > They don't actually need to exist here, just be loaded (and use absolute paths)
- newmod.add_ext_crate(false, "std", "std", {});
- newmod.add_ext_crate(false, "test", "test", {});
+ newmod.add_ext_crate(Span(), false, "std", "std", {});
+ newmod.add_ext_crate(Span(), false, "test", "test", {});
- newmod.add_item(false, "main", mv$(main_fn), {});
- newmod.add_item(false, "TESTS", mv$(tests_list), {});
+ newmod.add_item(Span(), false, "main", mv$(main_fn), {});
+ newmod.add_item(Span(), false, "TESTS", mv$(tests_list), {});
- crate.m_root_module.add_item(false, "test#", mv$(newmod), {});
+ crate.m_root_module.add_item(Span(), false, "test#", mv$(newmod), {});
crate.m_lang_items["mrustc-main"] = ::AST::Path("", { AST::PathNode("test#"), AST::PathNode("main") });
}
diff --git a/src/hir/crate_post_load.cpp b/src/hir/crate_post_load.cpp
index 81c5b029..a0733987 100644
--- a/src/hir/crate_post_load.cpp
+++ b/src/hir/crate_post_load.cpp
@@ -9,7 +9,7 @@
#include <macro_rules/macro_rules.hpp> // Used to update the crate name
-void HIR::Crate::post_load_update(const ::std::string& name)
+void HIR::Crate::post_load_update(const RcString& name)
{
// TODO: Do a pass across m_hir that
// 1. Updates all absolute paths with the crate name
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index afce2fe4..23b8fdf1 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -5,6 +5,8 @@
* hir/serialise.cpp
* - HIR (De)Serialisation for crate metadata
*/
+// TODO: Have an environment variable that controls if debug is enabled here.
+#define DEBUG_EXTRA_ENABLE && false
//#define DISABLE_DEBUG // Disable debug for this function - too hot
#include "hir.hpp"
#include "main_bindings.hpp"
@@ -22,13 +24,14 @@
class HirDeserialiser
{
- ::std::string m_crate_name;
+ RcString m_crate_name;
::HIR::serialise::Reader& m_in;
public:
HirDeserialiser(::HIR::serialise::Reader& in):
m_in(in)
{}
+ RcString read_istring() { return m_in.read_istring(); }
::std::string read_string() { return m_in.read_string(); }
bool read_bool() { return m_in.read_bool(); }
size_t deserialise_count() { return m_in.read_count(); }
@@ -78,10 +81,69 @@
return rv;
}
+ template<typename V>
+ ::std::map< RcString,V> deserialise_istrmap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::map< RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::unordered_map< RcString,V> deserialise_istrumap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::unordered_map<RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ DEBUG("- " << s);
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::unordered_multimap<RcString,V> deserialise_istrummap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::unordered_multimap<RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ DEBUG("- " << s);
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::map< ::HIR::SimplePath,V> deserialise_pathmap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::map< ::HIR::SimplePath, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = deserialise_simplepath();
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+
template<typename T>
::std::vector<T> deserialise_vec()
{
- TRACE_FUNCTION_F("<" << typeid(T).name() << ">");
+ TRACE_FUNCTION_FR("<" << typeid(T).name() << ">", m_in.get_pos());
size_t n = m_in.read_count();
DEBUG("n = " << n);
::std::vector<T> rv;
@@ -101,10 +163,14 @@
rv.push_back( cb() );
return rv;
}
+ ::HIR::Publicity deserialise_pub()
+ {
+ return (m_in.read_bool() ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none());
+ }
template<typename T>
::HIR::VisEnt<T> deserialise_visent()
{
- return ::HIR::VisEnt<T> { m_in.read_bool(), D<T>::des(*this) };
+ return ::HIR::VisEnt<T> { deserialise_pub(), D<T>::des(*this) };
}
template<typename T>
@@ -113,6 +179,7 @@
}
+ ::HIR::LifetimeDef deserialise_lifetimedef();
::HIR::LifetimeRef deserialise_lifetimeref();
::HIR::TypeRef deserialise_type();
::HIR::SimplePath deserialise_simplepath();
@@ -133,7 +200,7 @@
{
::HIR::ProcMacro pm;
TRACE_FUNCTION_FR("", "ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}");
- pm.name = m_in.read_string();
+ pm.name = m_in.read_istring();
pm.path = deserialise_simplepath();
pm.attributes = deserialise_vec< ::std::string>();
DEBUG("pm = ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}");
@@ -151,17 +218,17 @@
size_t method_count = m_in.read_count();
for(size_t i = 0; i < method_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> {
- m_in.read_bool(), m_in.read_bool(), deserialise_function()
+ deserialise_pub(), m_in.read_bool(), deserialise_function()
} ) );
}
size_t const_count = m_in.read_count();
for(size_t i = 0; i < const_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> {
- m_in.read_bool(), m_in.read_bool(), deserialise_constant()
+ deserialise_pub(), m_in.read_bool(), deserialise_constant()
} ) );
}
// m_src_module doesn't matter after typeck
@@ -180,7 +247,7 @@
size_t method_count = m_in.read_count();
for(size_t i = 0; i < method_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> {
is_spec, deserialise_function()
@@ -189,7 +256,7 @@
size_t const_count = m_in.read_count();
for(size_t i = 0; i < const_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> {
is_spec, deserialise_constant()
@@ -198,7 +265,7 @@
size_t static_count = m_in.read_count();
for(size_t i = 0; i < static_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_statics.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Static> {
is_spec, deserialise_static()
@@ -207,7 +274,7 @@
size_t type_count = m_in.read_count();
for(size_t i = 0; i < type_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_types.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> {
is_spec, deserialise_type()
@@ -236,16 +303,55 @@
// NOTE: This is set after loading.
//rv.m_exported = true;
rv.m_rules = deserialise_vec_c< ::MacroRulesArm>( [&](){ return deserialise_macrorulesarm(); });
- rv.m_source_crate = m_in.read_string();
+ rv.m_source_crate = m_in.read_istring();
if(rv.m_source_crate == "")
{
- assert(!m_crate_name.empty());
+ assert(m_crate_name != "");
rv.m_source_crate = m_crate_name;
}
return rv;
}
+ ::SimplePatIfCheck deserialise_simplepatifcheck() {
+ return ::SimplePatIfCheck {
+ static_cast<::MacroPatEnt::Type>(m_in.read_tag()),
+ deserialise_token()
+ };
+ }
+ ::SimplePatEnt deserialise_simplepatent() {
+ auto tag = static_cast< ::SimplePatEnt::Tag>( m_in.read_tag() );
+ switch(tag)
+ {
+ case ::SimplePatEnt::TAG_End:
+ return ::SimplePatEnt::make_End({});
+ case ::SimplePatEnt::TAG_LoopStart:
+ return ::SimplePatEnt::make_LoopStart({});
+ case ::SimplePatEnt::TAG_LoopNext:
+ return ::SimplePatEnt::make_LoopNext({});
+ case ::SimplePatEnt::TAG_LoopEnd:
+ return ::SimplePatEnt::make_LoopEnd({});
+ case ::SimplePatEnt::TAG_Jump:
+ return ::SimplePatEnt::make_Jump({ m_in.read_count() });
+ case ::SimplePatEnt::TAG_ExpectTok:
+ return SimplePatEnt::make_ExpectTok({
+ deserialise_token()
+ });
+ case ::SimplePatEnt::TAG_ExpectPat:
+ return SimplePatEnt::make_ExpectPat({
+ static_cast<::MacroPatEnt::Type>(m_in.read_tag()),
+ static_cast<unsigned>(m_in.read_count())
+ });
+ case SimplePatEnt::TAG_If:
+ return SimplePatEnt::make_If({
+ m_in.read_bool(),
+ m_in.read_count(),
+ deserialise_vec_c< SimplePatIfCheck>([&](){ return deserialise_simplepatifcheck(); })
+ });
+ default:
+ BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast<int>(tag));
+ }
+ }
::MacroPatEnt deserialise_macropatent() {
- auto s = m_in.read_string();
+ auto s = m_in.read_istring();
auto n = static_cast<unsigned int>(m_in.read_count());
auto type = static_cast< ::MacroPatEnt::Type>(m_in.read_tag());
::MacroPatEnt rv { mv$(s), mv$(n), mv$(type) };
@@ -268,21 +374,22 @@
case ::MacroPatEnt::PAT_BLOCK:
case ::MacroPatEnt::PAT_META:
case ::MacroPatEnt::PAT_ITEM:
+ case ::MacroPatEnt::PAT_VIS:
break;
default:
- throw "";
+ BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast<int>(rv.type) << " " << rv.type);
}
return rv;
}
::MacroRulesArm deserialise_macrorulesarm() {
::MacroRulesArm rv;
- rv.m_param_names = deserialise_vec< ::std::string>();
- rv.m_pattern = deserialise_vec_c< ::MacroPatEnt>( [&](){ return deserialise_macropatent(); } );
+ rv.m_param_names = deserialise_vec<RcString>();
+ rv.m_pattern = deserialise_vec_c< ::SimplePatEnt>( [&](){ return deserialise_simplepatent(); } );
rv.m_contents = deserialise_vec_c< ::MacroExpansionEnt>( [&](){ return deserialise_macroexpansionent(); } );
return rv;
}
::MacroExpansionEnt deserialise_macroexpansionent() {
- switch(m_in.read_tag())
+ switch(auto tag = m_in.read_tag())
{
case 0:
return ::MacroExpansionEnt( deserialise_token() );
@@ -305,7 +412,7 @@
});
}
default:
- throw "";
+ BUG(Span(), "Bad tag for MacroExpansionEnt - " << tag);
}
}
@@ -322,6 +429,8 @@
return ::Token::Data::make_None({});
case ::Token::Data::TAG_String:
return ::Token::Data::make_String( m_in.read_string() );
+ case ::Token::Data::TAG_IString:
+ return ::Token::Data::make_IString( m_in.read_istring() );
case ::Token::Data::TAG_Integer: {
auto dty = static_cast<eCoreType>(m_in.read_tag());
return ::Token::Data::make_Integer({ dty, m_in.read_u64c() });
@@ -331,7 +440,7 @@
return ::Token::Data::make_Float({ dty, m_in.read_double() });
}
default:
- throw ::std::runtime_error(FMT("Invalid Token data tag - " << tag));
+ BUG(Span(), "Bad tag for Token::Data - " << static_cast<int>(tag));
}
}
@@ -362,7 +471,7 @@
case ::MIR::Param::TAG_LValue: return deserialise_mir_lvalue();
case ::MIR::Param::TAG_Constant: return deserialise_mir_constant();
default:
- throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag));
+ BUG(Span(), "Bad tag for MIR::Param - " << tag);
}
}
::MIR::LValue deserialise_mir_lvalue() {
@@ -371,38 +480,21 @@
rv = deserialise_mir_lvalue_();
return rv;
}
+ ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper()
+ {
+ return ::MIR::LValue::Wrapper::from_inner(m_in.read_count());
+ }
::MIR::LValue deserialise_mir_lvalue_()
{
- switch(auto tag = m_in.read_tag())
- {
- #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ );
- _(Return, {})
- _(Argument, { static_cast<unsigned int>(m_in.read_count()) } )
- _(Local, static_cast<unsigned int>(m_in.read_count()) )
- _(Static, deserialise_path() )
- _(Field, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- _(Deref, { box$( deserialise_mir_lvalue() ) })
- _(Index, {
- box$( deserialise_mir_lvalue() ),
- box$( deserialise_mir_lvalue() )
- } )
- _(Downcast, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- #undef _
- default:
- throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag));
- }
+ auto root_v = m_in.read_count();
+ auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v));
+ return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() );
}
::MIR::RValue deserialise_mir_rvalue()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::RValue::TAG_##x: return ::MIR::RValue::make_##x( __VA_ARGS__ );
_(Use, deserialise_mir_lvalue() )
@@ -456,14 +548,14 @@
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::RValue - " << tag);
}
}
::MIR::Constant deserialise_mir_constant()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::Constant::TAG_##x: DEBUG("- " #x); return ::MIR::Constant::make_##x( __VA_ARGS__ );
_(Int, {
@@ -488,17 +580,24 @@
return ::MIR::Constant::make_Bytes( mv$(bytes) );
}
_(StaticString, m_in.read_string() )
- _(Const, { deserialise_path() } )
- _(ItemAddr, deserialise_path() )
+ _(Const, { box$(deserialise_path()) } )
+ _(ItemAddr, box$(deserialise_path()) )
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::Const - " << tag);
}
}
+ ::HIR::ExternType deserialise_externtype()
+ {
+ return ::HIR::ExternType {
+ deserialise_markings()
+ };
+ }
+
::HIR::TypeItem deserialise_typeitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0: {
auto spath = deserialise_simplepath();
@@ -517,13 +616,15 @@
return ::HIR::TypeItem( deserialise_trait() );
case 6:
return ::HIR::TypeItem( deserialise_union() );
+ case 7:
+ return ::HIR::TypeItem( deserialise_externtype() );
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::TypeItem - " << tag);
}
}
::HIR::ValueItem deserialise_valueitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0: {
auto spath = deserialise_simplepath();
@@ -541,7 +642,7 @@
case 5:
return ::HIR::ValueItem::make_StructConstructor({ deserialise_simplepath() });
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::ValueItem - " << tag);
}
}
@@ -655,7 +756,7 @@
::HIR::TraitValueItem deserialise_traitvalueitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::HIR::TraitValueItem::TAG_##x: DEBUG("- " #x); return ::HIR::TraitValueItem::make_##x( __VA_ARGS__ ); break;
_(Constant, deserialise_constant() )
@@ -663,15 +764,14 @@
_(Function, deserialise_function() )
#undef _
default:
- DEBUG("Invalid TraitValueItem tag");
- throw "";
+ BUG(Span(), "Bad tag for HIR::TraitValueItem - " << tag);
}
}
::HIR::AssociatedType deserialise_associatedtype()
{
return ::HIR::AssociatedType {
m_in.read_bool(),
- "", // TODO: Better lifetime type
+ deserialise_lifetimeref(),
deserialise_vec< ::HIR::TraitPath>(),
deserialise_type()
};
@@ -685,6 +785,9 @@
DEF_D( ::std::string,
return d.read_string(); );
template<>
+ DEF_D( RcString,
+ return d.read_istring(); );
+ template<>
DEF_D( bool,
return d.read_bool(); );
@@ -692,6 +795,9 @@
DEF_D( ::std::unique_ptr<T>,
return d.deserialise_ptr<T>(); )
+ template<typename T>
+ DEF_D( ::std::vector<T>,
+ return d.deserialise_vec<T>(); )
template<typename T, typename U>
struct D< ::std::pair<T,U> > { static ::std::pair<T,U> des(HirDeserialiser& d) {
auto a = D<T>::des(d);
@@ -702,6 +808,8 @@
DEF_D( ::HIR::VisEnt<T>,
return d.deserialise_visent<T>(); )
+ template<> DEF_D( ::HIR::LifetimeDef, return d.deserialise_lifetimedef(); )
+ template<> DEF_D( ::HIR::LifetimeRef, return d.deserialise_lifetimeref(); )
template<> DEF_D( ::HIR::TypeRef, return d.deserialise_type(); )
template<> DEF_D( ::HIR::SimplePath, return d.deserialise_simplepath(); )
template<> DEF_D( ::HIR::GenericPath, return d.deserialise_genericpath(); )
@@ -721,17 +829,40 @@
template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); )
template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); )
+ template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); )
template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); )
template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); )
template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); )
template<> DEF_D( ::HIR::ProcMacro, return d.deserialise_procmacro(); )
template<> DEF_D( ::HIR::TypeImpl, return d.deserialise_typeimpl(); )
+ template<> DEF_D( ::HIR::TraitImpl, return d.deserialise_traitimpl(); )
+ template<> DEF_D( ::HIR::MarkerImpl, return d.deserialise_markerimpl(); )
template<> DEF_D( ::MacroRulesPtr, return d.deserialise_macrorulesptr(); )
template<> DEF_D( unsigned int, return static_cast<unsigned int>(d.deserialise_count()); )
+ template<typename T>
+ DEF_D( ::HIR::Crate::ImplGroup<T>,
+ ::HIR::Crate::ImplGroup<T> rv;
+ rv.named = d.deserialise_pathmap< ::std::vector<::std::unique_ptr<T> > >();
+ rv.non_named = d.deserialise_vec< ::std::unique_ptr<T> >();
+ rv.generic = d.deserialise_vec< ::std::unique_ptr<T> >();
+ return rv;
+ )
+ template<>
+ DEF_D( ::HIR::Crate::MacroImport,
+ ::HIR::Crate::MacroImport rv;
+ rv.path = d.deserialise_simplepath();
+ return rv;
+ )
template<> DEF_D( ::HIR::ExternLibrary, return d.deserialise_extlib(); )
+ ::HIR::LifetimeDef HirDeserialiser::deserialise_lifetimedef()
+ {
+ ::HIR::LifetimeDef rv;
+ rv.m_name = m_in.read_istring();
+ return rv;
+ }
::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref()
{
::HIR::LifetimeRef rv;
@@ -756,7 +887,7 @@
{}
})
_(Generic, {
- m_in.read_string(),
+ m_in.read_istring(),
m_in.read_u16()
})
_(TraitObject, {
@@ -798,7 +929,7 @@
})
#undef _
default:
- throw ::std::runtime_error(FMT("Bad TypeRef tag - " << tag));
+ BUG(Span(), "Bad tag for HIR::TypeRef - " << tag);
}
return rv;
}
@@ -807,11 +938,11 @@
{
TRACE_FUNCTION;
// HACK! If the read crate name is empty, replace it with the name we're loaded with
- auto crate_name = m_in.read_string();
- auto components = deserialise_vec< ::std::string>();
+ auto crate_name = m_in.read_istring();
+ auto components = deserialise_vec< RcString>();
if( crate_name == "" && components.size() > 0)
{
- assert(!m_crate_name.empty());
+ assert(m_crate_name != "");
crate_name = m_crate_name;
}
return ::HIR::SimplePath {
@@ -837,13 +968,13 @@
::HIR::TraitPath HirDeserialiser::deserialise_traitpath()
{
auto gpath = deserialise_genericpath();
- auto tys = deserialise_strmap< ::HIR::TypeRef>();
+ auto tys = deserialise_istrmap< ::HIR::TypeRef>();
return ::HIR::TraitPath { mv$(gpath), {}, mv$(tys) };
}
::HIR::Path HirDeserialiser::deserialise_path()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0:
DEBUG("Generic");
@@ -852,7 +983,7 @@
DEBUG("Inherent");
return ::HIR::Path( ::HIR::Path::Data::Data_UfcsInherent {
box$( deserialise_type() ),
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams(),
deserialise_pathparams()
} );
@@ -861,11 +992,11 @@
return ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown {
box$( deserialise_type() ),
deserialise_genericpath(),
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams()
} );
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Path - " << tag);
}
}
@@ -874,7 +1005,7 @@
TRACE_FUNCTION;
::HIR::GenericParams params;
params.m_types = deserialise_vec< ::HIR::TypeParamDef>();
- params.m_lifetimes = deserialise_vec< ::std::string>();
+ params.m_lifetimes = deserialise_vec< ::HIR::LifetimeDef>();
params.m_bounds = deserialise_vec< ::HIR::GenericBound>();
DEBUG("params = " << params.fmt_args() << ", " << params.fmt_bounds());
return params;
@@ -882,7 +1013,7 @@
::HIR::TypeParamDef HirDeserialiser::deserialise_typaramdef()
{
auto rv = ::HIR::TypeParamDef {
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_type(),
m_in.read_bool()
};
@@ -891,7 +1022,7 @@
}
::HIR::GenericBound HirDeserialiser::deserialise_genericbound()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0:
return ::HIR::GenericBound::make_Lifetime({});
@@ -908,8 +1039,7 @@
deserialise_type()
});
default:
- DEBUG("Bad GenericBound tag");
- throw "";
+ BUG(Span(), "Bad tag for HIR::GenericBound - " << tag);
}
}
@@ -918,7 +1048,7 @@
TRACE_FUNCTION;
struct H {
static ::HIR::Enum::Class deserialise_enumclass(HirDeserialiser& des) {
- switch( des.m_in.read_tag() )
+ switch( auto tag = des.m_in.read_tag() )
{
case ::HIR::Enum::Class::TAG_Data:
return ::HIR::Enum::Class::make_Data( des.deserialise_vec<::HIR::Enum::DataVariant>() );
@@ -928,7 +1058,7 @@
des.deserialise_vec<::HIR::Enum::ValueVariant>()
});
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Enum::Class - " << tag);
}
}
};
@@ -940,7 +1070,7 @@
}
::HIR::Enum::DataVariant HirDeserialiser::deserialise_enumdatavariant()
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
DEBUG("Enum::DataVariant " << name);
return ::HIR::Enum::DataVariant {
mv$(name),
@@ -950,7 +1080,7 @@
}
::HIR::Enum::ValueVariant HirDeserialiser::deserialise_enumvaluevariant()
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
DEBUG("Enum::ValueVariant " << name);
return ::HIR::Enum::ValueVariant {
mv$(name),
@@ -963,7 +1093,7 @@
TRACE_FUNCTION;
auto params = deserialise_genericparams();
auto repr = static_cast< ::HIR::Union::Repr>( m_in.read_tag() );
- auto variants = deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >();
+ auto variants = deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >();
auto markings = deserialise_markings();
return ::HIR::Union {
@@ -972,13 +1102,13 @@
}
::HIR::Struct HirDeserialiser::deserialise_struct()
{
- TRACE_FUNCTION;
+ TRACE_FUNCTION_FR("", m_in.get_pos());
auto params = deserialise_genericparams();
auto repr = static_cast< ::HIR::Struct::Repr>( m_in.read_tag() );
DEBUG("params = " << params.fmt_args() << params.fmt_bounds());
::HIR::Struct::Data data;
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
case ::HIR::Struct::Data::TAG_Unit:
DEBUG("Unit");
@@ -990,16 +1120,18 @@
break;
case ::HIR::Struct::Data::TAG_Named:
DEBUG("Named");
- data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >() );
+ data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >() );
break;
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Struct::Data - " << tag);
}
+ auto align = static_cast<unsigned>(m_in.read_u64c());
+ DEBUG("align = " << align);
auto markings = deserialise_markings();
auto str_markings = deserialise_str_markings();
return ::HIR::Struct {
- mv$(params), repr, mv$(data), mv$(markings), mv$(str_markings)
+ mv$(params), repr, mv$(data), align, mv$(markings), mv$(str_markings)
};
}
::HIR::Trait HirDeserialiser::deserialise_trait()
@@ -1008,24 +1140,26 @@
::HIR::Trait rv {
deserialise_genericparams(),
- "", // TODO: Better type for lifetime
+ ::HIR::LifetimeRef(), // TODO: Better type for lifetime
{}
};
rv.m_is_marker = m_in.read_bool();
- rv.m_types = deserialise_strumap< ::HIR::AssociatedType>();
- rv.m_values = deserialise_strumap< ::HIR::TraitValueItem>();
- rv.m_value_indexes = deserialise_strummap< ::std::pair<unsigned int, ::HIR::GenericPath> >();
- rv.m_type_indexes = deserialise_strumap< unsigned int>();
+ rv.m_types = deserialise_istrumap< ::HIR::AssociatedType>();
+ rv.m_values = deserialise_istrumap< ::HIR::TraitValueItem>();
+ rv.m_value_indexes = deserialise_istrummap< ::std::pair<unsigned int, ::HIR::GenericPath> >();
+ rv.m_type_indexes = deserialise_istrumap< unsigned int>();
rv.m_all_parent_traits = deserialise_vec< ::HIR::TraitPath>();
+ rv.m_vtable_path = deserialise_simplepath();
return rv;
}
::HIR::Literal HirDeserialiser::deserialise_literal()
{
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
#define _(x, ...) case ::HIR::Literal::TAG_##x: return ::HIR::Literal::make_##x(__VA_ARGS__);
_(Invalid, {})
+ _(Defer, {})
_(List, deserialise_vec< ::HIR::Literal>() )
_(Variant, {
static_cast<unsigned int>(m_in.read_count()),
@@ -1038,7 +1172,7 @@
_(String, m_in.read_string() )
#undef _
default:
- throw "";
+ BUG(Span(), "Unknown HIR::Literal tag when deserialising - " << tag);
}
}
@@ -1068,7 +1202,7 @@
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
case 0:
return ::MIR::Statement::make_Assign({
@@ -1101,8 +1235,7 @@
deserialise_vec<unsigned int>()
});
default:
- ::std::cerr << "Bad tag for a MIR Statement" << ::std::endl;
- throw "";
+ BUG(Span(), "Bad tag for MIR::Statement - " << tag);
}
}
::MIR::Terminator HirDeserialiser::deserialise_mir_terminator()
@@ -1114,7 +1247,7 @@
}
::MIR::Terminator HirDeserialiser::deserialise_mir_terminator_()
{
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
#define _(x, ...) case ::MIR::Terminator::TAG_##x: return ::MIR::Terminator::make_##x( __VA_ARGS__ );
_(Incomplete, {})
@@ -1146,13 +1279,13 @@
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::Terminator - " << tag);
}
}
::MIR::SwitchValues HirDeserialiser::deserialise_mir_switchvalues()
{
TRACE_FUNCTION;
- switch(m_in.read_tag())
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::SwitchValues::TAG_##x: return ::MIR::SwitchValues::make_##x( __VA_ARGS__ );
_(Unsigned, deserialise_vec_c<uint64_t>([&](){ return m_in.read_u64c(); }))
@@ -1160,24 +1293,24 @@
_(String , deserialise_vec<::std::string>())
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::SwitchValues - " << tag);
}
}
::MIR::CallTarget HirDeserialiser::deserialise_mir_calltarget()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::CallTarget::TAG_##x: return ::MIR::CallTarget::make_##x( __VA_ARGS__ );
_(Value, deserialise_mir_lvalue() )
_(Path, deserialise_path() )
_(Intrinsic, {
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams()
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::CallTarget - " << tag);
}
}
@@ -1188,8 +1321,8 @@
::HIR::Module rv;
// m_traits doesn't need to be serialised
- rv.m_value_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >();
- rv.m_mod_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >();
+ rv.m_value_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >();
+ rv.m_mod_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >();
return rv;
}
@@ -1203,41 +1336,28 @@
{
::HIR::Crate rv;
- this->m_crate_name = m_in.read_string();
- assert(!this->m_crate_name.empty() && "Empty crate name loaded from metadata");
+ this->m_crate_name = m_in.read_istring();
+ assert(this->m_crate_name != "" && "Empty crate name loaded from metadata");
rv.m_crate_name = this->m_crate_name;
rv.m_root_module = deserialise_module();
- rv.m_type_impls = deserialise_vec< ::HIR::TypeImpl>();
-
- {
- size_t n = m_in.read_count();
- for(size_t i = 0; i < n; i ++)
- {
- auto p = deserialise_simplepath();
- rv.m_trait_impls.insert( ::std::make_pair( mv$(p), deserialise_traitimpl() ) );
- }
- }
- {
- size_t n = m_in.read_count();
- for(size_t i = 0; i < n; i ++)
- {
- auto p = deserialise_simplepath();
- rv.m_marker_impls.insert( ::std::make_pair( mv$(p), deserialise_markerimpl() ) );
- }
- }
+ rv.m_type_impls = D< ::HIR::Crate::ImplGroup<::HIR::TypeImpl> >::des(*this);
+ rv.m_trait_impls = deserialise_pathmap< ::HIR::Crate::ImplGroup<::HIR::TraitImpl>>();
+ rv.m_marker_impls = deserialise_pathmap< ::HIR::Crate::ImplGroup<::HIR::MarkerImpl>>();
- rv.m_exported_macros = deserialise_strumap< ::MacroRulesPtr>();
+ rv.m_exported_macros = deserialise_istrumap< ::MacroRulesPtr>();
+ rv.m_proc_macro_reexports = deserialise_istrumap< ::HIR::Crate::MacroImport>();
rv.m_lang_items = deserialise_strumap< ::HIR::SimplePath>();
{
size_t n = m_in.read_count();
for(size_t i = 0; i < n; i ++)
{
- auto ext_crate_name = m_in.read_string();
+ auto ext_crate_name = m_in.read_istring();
auto ext_crate_file = m_in.read_string();
auto ext_crate = ::HIR::ExternCrate {};
ext_crate.m_basename = ext_crate_file;
+ ext_crate.m_path = ext_crate_file;
rv.m_ext_crates.insert( ::std::make_pair( mv$(ext_crate_name), mv$(ext_crate) ) );
}
}
@@ -1251,11 +1371,11 @@
}
//}
-::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name)
+::HIR::CratePtr HIR_Deserialise(const ::std::string& filename)
{
try
{
- ::HIR::serialise::Reader in{ filename };
+ ::HIR::serialise::Reader in{ filename + ".hir" }; // HACK!
HirDeserialiser s { in };
::HIR::Crate rv = s.deserialise_crate();
diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp
index 874a80a7..3b981e26 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";
}
@@ -119,7 +152,7 @@ namespace {
m_os << "(";
for(const auto& fld : flds)
{
- m_os << (fld.is_public ? "pub " : "") << fld.ent << ", ";
+ m_os << fld.publicity << " " << fld.ent << ", ";
}
if( item.m_params.m_bounds.empty() )
{
@@ -142,7 +175,7 @@ namespace {
inc_indent();
for(const auto& fld : flds)
{
- m_os << indent() << (fld.second.is_public ? "pub " : "") << fld.first << ": " << fld.second.ent << ",\n";
+ m_os << indent() << fld.second.publicity << " " << fld.first << ": " << fld.second.ent << ",\n";
}
dec_indent();
m_os << indent() << "}\n";
@@ -298,33 +331,21 @@ namespace {
void visit(::HIR::ExprNode_Block& node) override
{
- if( node.m_nodes.size() == 0 ) {
- m_os << "{";
- if( node.m_value_node )
- {
- m_os << " ";
- this->visit_node_ptr(node.m_value_node);
- }
- m_os << " }";
+ m_os << "{\n";
+ inc_indent();
+ for(auto& sn : node.m_nodes) {
+ m_os << indent();
+ this->visit_node_ptr(sn);
+ m_os << ";\n";
}
- else {
- m_os << "{\n";
- inc_indent();
- for(auto& sn : node.m_nodes) {
- m_os << "\n";
- m_os << indent();
- this->visit_node_ptr(sn);
- m_os << ";\n";
- }
- if( node.m_value_node )
- {
- m_os << indent();
- this->visit_node_ptr(node.m_value_node);
- m_os << "\n";
- }
- dec_indent();
- m_os << indent() << "}";
+ if( node.m_value_node )
+ {
+ m_os << indent();
+ this->visit_node_ptr(node.m_value_node);
+ m_os << "\n";
}
+ dec_indent();
+ m_os << indent() << "}";
}
void visit(::HIR::ExprNode_Asm& node) override
@@ -363,6 +384,10 @@ namespace {
if( node.m_label != "" ) {
m_os << " '" << node.m_label;
}
+ if( node.m_value ) {
+ m_os << " ";
+ this->visit_node_ptr(node.m_value);
+ }
}
void visit(::HIR::ExprNode_Match& node) override
{
diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp
index 07504ea7..0512e557 100644
--- a/src/hir/expr.cpp
+++ b/src/hir/expr.cpp
@@ -19,6 +19,12 @@ void ::HIR::ExprVisitor::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& nod
}
void ::HIR::ExprVisitor::visit_node(::HIR::ExprNode& node) {
}
+void ::HIR::ExprVisitorDef::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) {
+ assert(node_ptr);
+ TRACE_FUNCTION_F(&*node_ptr << " " << typeid(*node_ptr).name());
+ node_ptr->visit(*this);
+ visit_type(node_ptr->m_res_type);
+}
DEF_VISIT(ExprNode_Block, node,
for(auto& subnode : node.m_nodes) {
visit_node_ptr(subnode);
@@ -83,6 +89,7 @@ DEF_VISIT(ExprNode_Borrow, node,
visit_node_ptr(node.m_value);
)
DEF_VISIT(ExprNode_Cast, node,
+ TRACE_FUNCTION_F("_Cast " << node.m_res_type);
visit_node_ptr(node.m_value);
)
DEF_VISIT(ExprNode_Unsize, node,
@@ -152,7 +159,7 @@ DEF_VISIT(ExprNode_PathValue, node,
)
DEF_VISIT(ExprNode_Variable, , )
DEF_VISIT(ExprNode_StructLiteral, node,
- visit_generic_path(::HIR::Visitor::PathContext::VALUE, node.m_path);
+ visit_path(::HIR::Visitor::PathContext::VALUE, node.m_path);
if( node.m_base_value )
visit_node_ptr(node.m_base_value);
for(auto& val : node.m_values)
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp
index 00d22c00..c87ae3a7 100644
--- a/src/hir/expr.hpp
+++ b/src/hir/expr.hpp
@@ -133,11 +133,11 @@ struct ExprNode_Return:
struct ExprNode_Loop:
public ExprNode
{
- ::std::string m_label;
+ RcString m_label;
::HIR::ExprNodeP m_code;
bool m_diverges = false;
- ExprNode_Loop(Span sp, ::std::string label, ::HIR::ExprNodeP code):
+ ExprNode_Loop(Span sp, RcString label, ::HIR::ExprNodeP code):
//ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()),
ExprNode(mv$(sp), ::HIR::TypeRef()),
m_label( mv$(label) ),
@@ -149,11 +149,11 @@ struct ExprNode_Loop:
struct ExprNode_LoopControl:
public ExprNode
{
- ::std::string m_label;
+ RcString m_label;
bool m_continue;
::HIR::ExprNodeP m_value;
- ExprNode_LoopControl(Span sp, ::std::string label, bool cont, ::HIR::ExprNodeP value={}):
+ ExprNode_LoopControl(Span sp, RcString label, bool cont, ::HIR::ExprNodeP value={}):
ExprNode(mv$(sp), ::HIR::TypeRef::new_diverge()),
m_label( mv$(label) ),
m_continue( cont ),
@@ -409,6 +409,10 @@ struct ExprNode_Index:
::HIR::ExprNodeP m_value;
::HIR::ExprNodeP m_index;
+ struct {
+ ::HIR::TypeRef index_ty;
+ } m_cache;
+
ExprNode_Index(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprNodeP index):
ExprNode(mv$(sp)),
m_value( mv$(val) ),
@@ -539,7 +543,7 @@ struct ExprNode_CallMethod:
public ExprNode
{
::HIR::ExprNodeP m_value;
- ::std::string m_method;
+ RcString m_method;
::HIR::PathParams m_params;
::std::vector< ::HIR::ExprNodeP> m_args;
@@ -553,7 +557,7 @@ struct ExprNode_CallMethod:
// - A pool of ivars to use for searching for trait impls
::std::vector<unsigned int> m_trait_param_ivars;
- ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, ::std::string method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args):
+ ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, RcString method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args):
ExprNode( mv$(sp) ),
m_value( mv$(val) ),
m_method( mv$(method_name) ),
@@ -570,9 +574,9 @@ struct ExprNode_Field:
public ExprNode
{
::HIR::ExprNodeP m_value;
- ::std::string m_field;
+ RcString m_field;
- ExprNode_Field(Span sp, ::HIR::ExprNodeP val, ::std::string field):
+ ExprNode_Field(Span sp, ::HIR::ExprNodeP val, RcString field):
ExprNode(mv$(sp)),
m_value( mv$(val) ),
m_field( mv$(field) )
@@ -677,10 +681,10 @@ struct ExprNode_PathValue:
struct ExprNode_Variable:
public ExprNode
{
- ::std::string m_name;
+ RcString m_name;
unsigned int m_slot;
- ExprNode_Variable(Span sp, ::std::string name, unsigned int slot):
+ ExprNode_Variable(Span sp, RcString name, unsigned int slot):
ExprNode(mv$(sp)),
m_name( mv$(name) ),
m_slot( slot )
@@ -692,9 +696,9 @@ struct ExprNode_Variable:
struct ExprNode_StructLiteral:
public ExprNode
{
- typedef ::std::vector< ::std::pair< ::std::string, ExprNodeP > > t_values;
+ typedef ::std::vector< ::std::pair< RcString, ExprNodeP > > t_values;
- ::HIR::GenericPath m_path;
+ ::HIR::Path m_path;
bool m_is_struct;
::HIR::ExprNodeP m_base_value;
t_values m_values;
@@ -702,7 +706,7 @@ struct ExprNode_StructLiteral:
/// Monomorphised types of each field.
::std::vector< ::HIR::TypeRef> m_value_types;
- ExprNode_StructLiteral(Span sp, ::HIR::GenericPath path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values):
+ ExprNode_StructLiteral(Span sp, ::HIR::Path path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values):
ExprNode( mv$(sp) ),
m_path( mv$(path) ),
m_is_struct( is_struct ),
@@ -719,12 +723,12 @@ struct ExprNode_UnionLiteral:
public ExprNode
{
::HIR::GenericPath m_path;
- ::std::string m_variant_name;
+ RcString m_variant_name;
::HIR::ExprNodeP m_value;
unsigned int m_variant_index = ~0;
- ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, ::std::string name, ::HIR::ExprNodeP value):
+ ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, RcString name, ::HIR::ExprNodeP value):
ExprNode( mv$(sp) ),
m_path( mv$(path) ),
m_variant_name( mv$(name) ),
@@ -793,8 +797,10 @@ struct ExprNode_Closure:
Mut,
Once,
} m_class = Class::Unknown;
+ bool m_is_copy = false;
// - Path to the generated closure type
+ const ::HIR::Struct* m_obj_ptr = nullptr;
::HIR::GenericPath m_obj_path_base;
::HIR::GenericPath m_obj_path;
::std::vector< ::HIR::ExprNodeP> m_captures;
@@ -866,6 +872,8 @@ class ExprVisitorDef:
public:
#define NV(nt) virtual void visit(nt& n);
+ virtual void visit_node_ptr(::std::unique_ptr<ExprNode>& node_ptr) override;
+
NV(ExprNode_Block)
NV(ExprNode_Asm)
NV(ExprNode_Return)
diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp
index fcef34bd..7f493a0d 100644
--- a/src/hir/expr_ptr.cpp
+++ b/src/hir/expr_ptr.cpp
@@ -45,6 +45,13 @@
}
+const Span& HIR::ExprPtr::span() const
+{
+ static Span static_sp;
+ if( *this )
+ return (*this)->span();
+ return static_sp;
+}
const ::MIR::Function* HIR::ExprPtr::get_mir_opt() const
{
if(!this->m_mir)
@@ -83,6 +90,15 @@ void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir)
{
assert( !this->m_mir );
m_mir = ::std::move(mir);
+ // Reset the HIR tree to be a placeholder node (thus freeing the backing memory)
+ if( false && node )
+ {
+ auto sp = node->span();
+ node = ExprPtrInner(::std::unique_ptr<HIR::ExprNode>(new ::HIR::ExprNode_Loop(
+ sp, "",
+ ::std::unique_ptr<HIR::ExprNode>(new ::HIR::ExprNode_Tuple(sp, {}))
+ )));
+ }
}
diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp
index 2f0f30e4..512921eb 100644
--- a/src/hir/expr_ptr.hpp
+++ b/src/hir/expr_ptr.hpp
@@ -105,6 +105,7 @@ public:
::HIR::ExprNode* get() const { return node.get(); }
void reset(::HIR::ExprNode* p) { node.reset(p); }
+ const Span& span() const;
::HIR::ExprNode& operator*() { return *node; }
const ::HIR::ExprNode& operator*() const { return *node; }
::HIR::ExprNode* operator->() { return &*node; }
diff --git a/src/hir/expr_state.hpp b/src/hir/expr_state.hpp
index 11fffe67..139c400d 100644
--- a/src/hir/expr_state.hpp
+++ b/src/hir/expr_state.hpp
@@ -16,13 +16,15 @@ public:
::HIR::SimplePath m_mod_path;
const ::HIR::Module& m_module;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits;
enum class Stage {
Created,
+ ConstEvalRequest,
+ ConstEval,
TypecheckRequest,
Typecheck,
MirRequest,
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index 7d1b05a8..e3cba9e9 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -23,15 +23,18 @@
::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path);
::HIR::SimplePath path_Sized;
-::std::string g_core_crate;
-::std::string g_crate_name;
+RcString g_core_crate;
+RcString g_crate_name;
::HIR::Crate* g_crate_ptr = nullptr;
const ::AST::Crate* g_ast_crate_ptr;
// --------------------------------------------------------------------
-::std::string LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r)
+HIR::LifetimeRef LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r)
{
- return r.name().name;
+ return HIR::LifetimeRef(
+ // TODO: names?
+ r.binding()
+ );
}
::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized)
@@ -48,7 +51,7 @@ const ::AST::Crate* g_ast_crate_ptr;
if( gp.lft_params().size() > 0 )
{
for(const auto& lft_def : gp.lft_params())
- rv.m_lifetimes.push_back( lft_def.name().name );
+ rv.m_lifetimes.push_back( HIR::LifetimeDef { lft_def.name().name } );
}
if( gp.bounds().size() > 0 )
{
@@ -156,28 +159,26 @@ const ::AST::Crate* g_ast_crate_ptr;
}
};
- TU_MATCH(::AST::Pattern::Data, (pat.data()), (e),
- (MaybeBind,
+ TU_MATCH_HDRA( (pat.data()), {)
+ TU_ARMA(MaybeBind, e) {
BUG(pat.span(), "Encountered MaybeBind pattern");
- ),
- (Macro,
+ }
+ TU_ARMA(Macro, e) {
BUG(pat.span(), "Encountered Macro pattern");
- ),
- (Any,
+ }
+ TU_ARMA(Any, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Any({})
};
- ),
- (Box,
+ TU_ARMA(Box, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Box({
box$(LowerHIR_Pattern( *e.sub ))
})
};
- ),
- (Ref,
+ TU_ARMA(Ref, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Ref({
@@ -185,8 +186,7 @@ const ::AST::Crate* g_ast_crate_ptr;
box$(LowerHIR_Pattern( *e.sub ))
})
};
- ),
- (Tuple,
+ TU_ARMA(Tuple, e) {
auto leading = H::lowerhir_patternvec( e.start );
auto trailing = H::lowerhir_patternvec( e.end );
@@ -209,16 +209,14 @@ const ::AST::Crate* g_ast_crate_ptr;
})
};
}
- ),
-
- (StructTuple,
+ }
+ TU_ARMA(StructTuple, e) {
unsigned int leading_count = e.tup_pat.start.size();
unsigned int trailing_count = e.tup_pat.end .size();
- TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (e.path.m_bindings.value), {)
+ default:
BUG(pat.span(), "Encountered StructTuple pattern not pointing to a enum variant or a struct - " << e.path);
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
assert( pb.enum_ || pb.hir );
unsigned int field_count;
if( pb.enum_ ) {
@@ -268,8 +266,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(sub_patterns)
})
};
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pb) {
assert( pb.struct_ || pb.hir );
unsigned int field_count;
if( pb.struct_ ) {
@@ -317,20 +315,32 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(sub_patterns)
})
};
- )
- )
- ),
- (Struct,
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > sub_patterns;
+ }
+ }
+ }
+ TU_ARMA(Struct, e) {
+ ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > sub_patterns;
for(const auto& sp : e.sub_patterns)
sub_patterns.push_back( ::std::make_pair(sp.first, LowerHIR_Pattern(sp.second)) );
+ if( e.sub_patterns.empty() && !e.is_exhaustive ) {
+ if( e.path.m_bindings.value.is_EnumVar() ) {
+ return ::HIR::Pattern {
+ mv$(binding),
+ ::HIR::Pattern::Data::make_EnumStruct({
+ LowerHIR_GenericPath(pat.span(), e.path),
+ nullptr, 0,
+ mv$(sub_patterns),
+ e.is_exhaustive
+ })
+ };
+ }
+ }
- TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (e.path.m_bindings.type), {)
+ default:
BUG(pat.span(), "Encountered Struct pattern not pointing to a enum variant or a struct - " << e.path);
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_EnumStruct({
@@ -340,8 +350,8 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- ),
- (TypeAlias,
+ }
+ TU_ARMA(TypeAlias, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Struct({
@@ -351,8 +361,8 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Struct({
@@ -362,11 +372,11 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- )
- )
- ),
+ }
+ }
+ }
- (Value,
+ TU_ARMA(Value, e) {
struct H {
static ::HIR::CoreType get_int_type(const Span& sp, const ::eCoreType ct) {
switch(ct)
@@ -450,8 +460,8 @@ const ::AST::Crate* g_ast_crate_ptr;
})
};
}
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, e) {
::std::vector< ::HIR::Pattern> leading;
for(const auto& sp : e.sub_pats)
leading.push_back( LowerHIR_Pattern(sp) );
@@ -461,8 +471,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(leading)
})
};
- ),
- (SplitSlice,
+ }
+ TU_ARMA(SplitSlice, e) {
::std::vector< ::HIR::Pattern> leading;
for(const auto& sp : e.leading)
leading.push_back( LowerHIR_Pattern(sp) );
@@ -485,8 +495,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(trailing)
})
};
- )
- )
+ }
+ }
throw "unreachable";
}
@@ -621,7 +631,17 @@ const ::AST::Crate* g_ast_crate_ptr;
return ::HIR::Path( LowerHIR_GenericPath(sp, path) );
),
(UFCS,
- if( e.nodes.size() != 1 )
+ if( e.nodes.size() == 0 )
+ {
+ if( !e.trait )
+ TODO(sp, "Handle UFCS inherent and no nodes - " << path);
+ if( e.trait->is_valid() )
+ TODO(sp, "Handle UFCS w/ trait and no nodes - " << path);
+ auto type = LowerHIR_Type(*e.type);
+ ASSERT_BUG(sp, type.m_data.is_Path(), "No nodes and non-Path type - " << path);
+ return mv$(type.m_data.as_Path().path);
+ }
+ if( e.nodes.size() > 1 )
TODO(sp, "Handle UFCS with multiple nodes - " << path);
// - No associated type bounds allowed in UFCS paths
auto params = LowerHIR_PathParams(sp, e.nodes.front().args(), false);
@@ -731,8 +751,9 @@ const ::AST::Crate* g_ast_crate_ptr;
{
if( ptr->m_datatype == CORETYPE_UINT || ptr->m_datatype == CORETYPE_ANY )
{
- if( ptr->m_value > UINT_MAX ) {
- ERROR(ty.span(), E0000, "Array size out of bounds - " << ptr->m_value << " > " << UINT_MAX);
+ // TODO: Chage the HIR format to support very large arrays
+ if( ptr->m_value >= UINT64_MAX ) {
+ ERROR(ty.span(), E0000, "Array size out of bounds - 0x" << ::std::hex << ptr->m_value << " > 0x" << UINT64_MAX << " in " << ::std::dec << ty);
}
auto size_val = static_cast<unsigned int>( ptr->m_value );
return ::HIR::TypeRef::new_array( mv$(inner), size_val );
@@ -750,9 +771,9 @@ const ::AST::Crate* g_ast_crate_ptr;
TU_IFLET(::AST::Path::Class, e.path.m_class, Local, l,
unsigned int slot;
// NOTE: TypeParameter is unused
- TU_IFLET(::AST::PathBinding, e.path.binding(), Variable, p,
- slot = p.slot;
- )
+ if( const auto* p = e.path.m_bindings.value.opt_Variable() ) {
+ slot = p->slot;
+ }
else {
BUG(ty.span(), "Unbound local encountered in " << e.path);
}
@@ -768,7 +789,7 @@ const ::AST::Crate* g_ast_crate_ptr;
for(const auto& t : e.traits)
{
DEBUG("t = " << t.path);
- const auto& tb = t.path.binding().as_Trait();
+ const auto& tb = t.path.m_bindings.type.as_Trait();
assert( tb.trait_ || tb.hir );
if( (tb.trait_ ? tb.trait_->is_marker() : tb.hir->m_is_marker) )
{
@@ -851,9 +872,20 @@ const ::AST::Crate* g_ast_crate_ptr;
namespace {
template<typename T>
- ::HIR::VisEnt<T> new_visent(bool pub, T v) {
+ ::HIR::VisEnt<T> new_visent(HIR::Publicity pub, T v) {
return ::HIR::VisEnt<T> { pub, mv$(v) };
}
+
+ ::HIR::SimplePath get_parent_module(const ::HIR::ItemPath& p) {
+ const ::HIR::ItemPath* parent_ip = p.parent;
+ assert(parent_ip);
+ while(parent_ip->name && parent_ip->name[0] == '#')
+ {
+ parent_ip = parent_ip->parent;
+ assert(parent_ip);
+ }
+ return parent_ip->get_simple_path();
+ }
}
::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::AttributeList& attrs)
@@ -861,6 +893,9 @@ namespace {
TRACE_FUNCTION_F(path);
::HIR::Struct::Data data;
+ auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) );
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
TU_MATCH(::AST::StructData, (ent.m_data), (e),
(Unit,
data = ::HIR::Struct::Data::make_Unit({});
@@ -869,70 +904,76 @@ namespace {
::HIR::Struct::Data::Data_Tuple fields;
for(const auto& field : e.ents)
- fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } );
+ fields.push_back( { get_pub(field.m_is_public), LowerHIR_Type(field.m_type) } );
data = ::HIR::Struct::Data::make_Tuple( mv$(fields) );
),
(Struct,
::HIR::Struct::Data::Data_Named fields;
for(const auto& field : e.ents)
- fields.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) );
+ fields.push_back( ::std::make_pair( field.m_name, new_visent( get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) );
data = ::HIR::Struct::Data::make_Named( mv$(fields) );
)
)
- auto struct_repr = ::HIR::Struct::Repr::Rust;
+ auto rv = ::HIR::Struct {
+ LowerHIR_GenericParams(ent.params(), nullptr),
+ ::HIR::Struct::Repr::Rust,
+ mv$(data)
+ };
+
if( const auto* attr_repr = attrs.get("repr") )
{
- ASSERT_BUG(Span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr);
- bool is_c = false;
- bool is_simd = false;
- bool is_packed = false;
- ASSERT_BUG(Span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(attr_repr->span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(attr_repr->span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr);
+ // TODO: Change reprs to be a flag set (instead of an enum)?
+ // (Or at least make C be a flag)
for( const auto& a : attr_repr->items() )
{
- ASSERT_BUG(Span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
const auto& repr_str = a.name();
if( repr_str == "C" ) {
- is_c = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ if( rv.m_repr == ::HIR::Struct::Repr::Aligned )
+ {
+ }
+ else if( rv.m_repr != ::HIR::Struct::Repr::Packed )
+ {
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::C;
+ }
}
else if( repr_str == "packed" ) {
- is_packed = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust || rv.m_repr == ::HIR::Struct::Repr::C, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Packed;
}
else if( repr_str == "simd" ) {
- is_simd = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Simd;
+ }
+ else if( repr_str == "transparent" ) {
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Transparent;
+ }
+ else if( repr_str == "align" ) {
+ //ASSERT_BUG(a.span(), a.has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr != ::HIR::Struct::Repr::Packed, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ //rv.m_repr = ::HIR::Struct::Repr::Aligned;
+ //rv.m_forced_alignment = ::std::stol(a.string());
}
else {
TODO(a.span(), "Handle struct repr '" << repr_str << "'");
}
}
-
- if( is_packed ) {
- // TODO: What if `simd` is present?
- // NOTE: repr(packed,C) is treated as the same as repr(packed) in mrustc
- struct_repr = ::HIR::Struct::Repr::Packed;
- }
- else if( is_c ) {
- // TODO: What if `simd` is present?
- struct_repr = ::HIR::Struct::Repr::C;
- }
- else if( is_simd ) {
- struct_repr = ::HIR::Struct::Repr::Simd;
- }
- else {
- }
}
- return ::HIR::Struct {
- LowerHIR_GenericParams(ent.params(), nullptr),
- struct_repr,
- mv$(data)
- };
+ return rv;
}
-::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function<void(::std::string, ::HIR::Struct)> push_struct)
+::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function<void(RcString, ::HIR::Struct)> push_struct)
{
-
// 1. Figure out what sort of enum this is (value or data)
bool has_value = false;
bool has_data = false;
@@ -1029,14 +1070,14 @@ namespace {
{
::HIR::Struct::Data::Data_Tuple fields;
for(const auto& field : ve->m_sub_types)
- fields.push_back( new_visent(true, LowerHIR_Type(field)) );
+ fields.push_back( new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field)) );
data = ::HIR::Struct::Data::make_Tuple( mv$(fields) );
}
else if( const auto* ve = var.m_data.opt_Struct() )
{
::HIR::Struct::Data::Data_Named fields;
for(const auto& field : ve->m_fields)
- fields.push_back( ::std::make_pair( field.m_name, new_visent(true, LowerHIR_Type(field.m_type)) ) );
+ fields.push_back( ::std::make_pair( field.m_name, new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field.m_type)) ) );
data = ::HIR::Struct::Data::make_Named( mv$(fields) );
}
else
@@ -1044,7 +1085,7 @@ namespace {
throw "";
}
- auto ty_name = FMT(path.name << "#" << var.m_name);
+ auto ty_name = RcString::new_interned(FMT(path.name << "#" << var.m_name));
push_struct(
ty_name,
::HIR::Struct {
@@ -1082,6 +1123,9 @@ namespace {
}
::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::AttributeList& attrs)
{
+ auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) );
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
auto repr = ::HIR::Union::Repr::Rust;
if( const auto* attr_repr = attrs.get("repr") )
@@ -1100,7 +1144,7 @@ namespace {
::HIR::Struct::Data::Data_Named variants;
for(const auto& field : f.m_variants)
- variants.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) );
+ variants.push_back( ::std::make_pair( field.m_name, new_visent(get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) );
return ::HIR::Union {
LowerHIR_GenericParams(f.m_params, nullptr),
@@ -1116,14 +1160,14 @@ namespace {
bool trait_reqires_sized = false;
auto params = LowerHIR_GenericParams(f.params(), &trait_reqires_sized);
- ::std::string lifetime;
+ ::HIR::LifetimeRef lifetime;
::std::vector< ::HIR::TraitPath> supertraits;
for(const auto& st : f.supertraits()) {
if( st.ent.path.is_valid() ) {
supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent.path) );
}
else {
- lifetime = "static";
+ lifetime = ::HIR::LifetimeRef::new_static();
}
}
::HIR::Trait rv {
@@ -1150,32 +1194,36 @@ namespace {
TU_MATCH_DEF(::AST::Item, (item.data), (i),
(
- BUG(item.data.span, "Encountered unexpected item type in trait");
+ BUG(item.span, "Encountered unexpected item type in trait");
),
(None,
// Ignore.
),
+ (MacroInv,
+ // Ignore.
+ ),
(Type,
bool is_sized = true;
::std::vector< ::HIR::TraitPath> trait_bounds;
- ::std::string lifetime_bound;
+ ::HIR::LifetimeRef lifetime_bound;
auto gps = LowerHIR_GenericParams(i.params(), &is_sized);
+
for(auto& b : gps.m_bounds)
{
TU_MATCH(::HIR::GenericBound, (b), (be),
(TypeLifetime,
- ASSERT_BUG(item.data.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid lifetime bound on associated type");
+ ASSERT_BUG(item.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid lifetime bound on associated type");
lifetime_bound = mv$(be.valid_for);
),
(TraitBound,
- ASSERT_BUG(item.data.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid trait bound on associated type");
+ ASSERT_BUG(item.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid trait bound on associated type");
trait_bounds.push_back( mv$(be.trait) );
),
(Lifetime,
- BUG(item.data.span, "Unexpected lifetime-lifetime bound on associated type");
+ BUG(item.span, "Unexpected lifetime-lifetime bound on associated type");
),
(TypeEquality,
- BUG(item.data.span, "Unexpected type equality bound on associated type");
+ BUG(item.span, "Unexpected type equality bound on associated type");
)
)
}
@@ -1188,7 +1236,7 @@ namespace {
),
(Function,
::HIR::TypeRef self_type {"Self", 0xFFFF};
- auto fcn = LowerHIR_Function(item_path, item.data.attrs, i, self_type);
+ auto fcn = LowerHIR_Function(item_path, item.attrs, i, self_type);
fcn.m_save_code = true;
rv.m_values.insert( ::std::make_pair(item.name, ::HIR::TraitValueItem::make_Function( mv$(fcn) )) );
),
@@ -1248,13 +1296,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 {
@@ -1325,12 +1389,15 @@ namespace {
};
}
-void _add_mod_ns_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::TypeItem ti) {
+void _add_mod_ns_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::TypeItem ti) {
mod.m_mod_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::TypeItem> { is_pub, mv$(ti) }) ) );
}
-void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::ValueItem ti) {
+void _add_mod_val_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::ValueItem ti) {
mod.m_value_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::ValueItem> { is_pub, mv$(ti) }) ) );
}
+void _add_mod_mac_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::MacroItem ti) {
+ mod.m_macro_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::MacroItem> { is_pub, mv$(ti) }) ) );
+}
::HIR::Module LowerHIR_Module(const ::AST::Module& ast_mod, ::HIR::ItemPath path, ::std::vector< ::HIR::SimplePath> traits)
{
@@ -1339,10 +1406,13 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
mod.m_traits = mv$(traits);
+ auto priv_path = ::HIR::Publicity::new_priv( path.get_simple_path() );
+ auto get_pub = [&](bool is_pub)->::HIR::Publicity{ return (is_pub ? ::HIR::Publicity::new_global() : priv_path); };
+
// Populate trait list
for(const auto& item : ast_mod.m_type_items)
{
- if( item.second.path.binding().is_Trait() ) {
+ if( item.second.path.m_bindings.type.is_Trait() ) {
auto sp = LowerHIR_SimplePath(Span(), item.second.path);
if( ::std::find(mod.m_traits.begin(), mod.m_traits.end(), sp) == mod.m_traits.end() )
mod.m_traits.push_back( mv$(sp) );
@@ -1355,21 +1425,23 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
if( submod_ptr )
{
auto& submod = *submod_ptr;
- ::std::string name = FMT("#" << i);
+ auto name = RcString::new_interned(FMT("#" << i));
auto item_path = ::HIR::ItemPath(path, name.c_str());
auto ti = ::HIR::TypeItem::make_Module( LowerHIR_Module(submod, item_path, mod.m_traits) );
- _add_mod_ns_item( mod, mv$(name), false, mv$(ti) );
+ _add_mod_ns_item( mod, mv$(name), get_pub(false), mv$(ti) );
}
}
for( const auto& item : ast_mod.items() )
{
- const auto& sp = item.data.span;
+ const auto& sp = item.span;
auto item_path = ::HIR::ItemPath(path, item.name.c_str());
DEBUG(item_path << " " << item.data.tag_str());
TU_MATCH(::AST::Item, (item.data), (e),
(None,
),
+ (Macro,
+ ),
(MacroInv,
// Valid.
//BUG(sp, "Stray macro invocation in " << path);
@@ -1380,7 +1452,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
TODO(sp, "Expand ExternBlock");
}
// Insert a record of the `link` attribute
- for(const auto& a : item.data.attrs.m_items)
+ for(const auto& a : item.attrs.m_items)
{
if( a.name() != "link" ) continue ;
@@ -1412,44 +1484,53 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
// Ignore - The index is used to add `Import`s
),
(Module,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Module(e, mv$(item_path)) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Module(e, mv$(item_path)) );
),
(Crate,
// All 'extern crate' items should be normalised into a list in the crate root
// - If public, add a namespace import here referring to the root of the imported crate
- _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) );
),
(Type,
- _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) );
+ if( e.type().m_data.is_Any() )
+ {
+ if( !e.params().lft_params().empty() || !e.params().ty_params().empty() || !e.params().bounds().empty() )
+ {
+ ERROR(item.span, E0000, "Generics on extern type");
+ }
+ _add_mod_ns_item(mod, item.name, get_pub(item.is_pub), ::HIR::ExternType {});
+ break;
+ }
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) );
),
(Struct,
/// Add value reference
if( e.m_data.is_Unit() ) {
- _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) );
+ _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) );
}
else if( e.m_data.is_Tuple() ) {
- _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) );
+ _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) );
}
else {
}
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e, item.data.attrs) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Struct(item_path, e, item.attrs) );
),
(Enum,
- auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, item.is_pub, mv$(str)); });
- _add_mod_ns_item( mod, item.name, item.is_pub, mv$(enm) );
+ auto enm = LowerHIR_Enum(item_path, e, item.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, get_pub(item.is_pub), mv$(str)); });
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), mv$(enm) );
),
(Union,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Union(item_path, e, item.data.attrs) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Union(item_path, e, item.attrs) );
),
(Trait,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Trait(item_path.get_simple_path(), e) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Trait(item_path.get_simple_path(), e) );
),
(Function,
- _add_mod_val_item(mod, item.name, item.is_pub, LowerHIR_Function(item_path, item.data.attrs, e, ::HIR::TypeRef{}));
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), LowerHIR_Function(item_path, item.attrs, e, ::HIR::TypeRef{}));
),
(Static,
if( e.s_class() == ::AST::Static::CONST )
- _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Constant(::HIR::Constant {
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Constant(::HIR::Constant {
::HIR::GenericParams {},
LowerHIR_Type( e.type() ),
LowerHIR_Expr( e.value() )
@@ -1460,10 +1541,10 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
// If there's no code, demangle the name (TODO: By ABI) and set linkage.
if( linkage.name == "" && ! e.value().is_valid() )
{
- linkage.name = item.name;
+ linkage.name = item.name.c_str();
}
- _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Static(::HIR::Static {
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Static(::HIR::Static {
mv$(linkage),
(e.s_class() == ::AST::Static::MUT),
LowerHIR_Type( e.type() ),
@@ -1481,17 +1562,15 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
if( ie.second.is_import ) {
auto hir_path = LowerHIR_SimplePath( sp, ie.second.path );
::HIR::TypeItem ti;
- TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb),
- (
+ if( const auto* pb = ie.second.path.m_bindings.type.opt_EnumVar() ) {
+ DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)");
+ ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb->idx });
+ }
+ else {
DEBUG("Import NS " << ie.first << " = " << hir_path);
ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), false, 0 });
- ),
- (EnumVar,
- DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)");
- ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb.idx });
- )
- )
- _add_mod_ns_item(mod, ie.first, ie.second.is_pub, mv$(ti));
+ }
+ _add_mod_ns_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(ti));
}
}
for( const auto& ie : ast_mod.m_value_items )
@@ -1501,17 +1580,26 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
auto hir_path = LowerHIR_SimplePath( sp, ie.second.path );
::HIR::ValueItem vi;
- TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (ie.second.path.m_bindings.value), {)
+ default:
DEBUG("Import VAL " << ie.first << " = " << hir_path);
vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), false, 0 });
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
DEBUG("Import VAL " << ie.first << " = " << hir_path << " (Enum Variant)");
vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), true, pb.idx });
- )
- )
- _add_mod_val_item(mod, ie.first, ie.second.is_pub, mv$(vi));
+ }
+ }
+ _add_mod_val_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(vi));
+ }
+ }
+
+ for( const auto& ie : ast_mod.m_macro_imports )
+ {
+ //const auto& sp = mod_span;
+ if( ie.is_pub )
+ {
+ auto mi = ::HIR::MacroItem::make_Import({ ::HIR::SimplePath(ie.path.front(), ::std::vector<RcString>(ie.path.begin()+1, ie.path.end())) });
+ _add_mod_mac_item( mod, ie.name, get_pub(true), mv$(mi) );
}
}
@@ -1541,13 +1629,14 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
{
if( !i.data.is_Impl() ) continue;
const auto& impl = i.data.as_Impl();
+ const Span impl_span;
auto params = LowerHIR_GenericParams(impl.def().params(), nullptr);
TRACE_FUNCTION_F("IMPL " << impl.def());
if( impl.def().trait().ent.is_valid() )
{
- const auto& pb = impl.def().trait().ent.binding();
+ const auto& pb = impl.def().trait().ent.m_bindings.type;
ASSERT_BUG(Span(), pb.is_Trait(), "Binding for trait path in impl isn't a Trait - " << impl.def().trait().ent);
ASSERT_BUG(Span(), pb.as_Trait().trait_ || pb.as_Trait().hir, "Trait pointer for trait path in impl isn't set");
bool is_marker = (pb.as_Trait().trait_ ? pb.as_Trait().trait_->is_marker() : pb.as_Trait().hir->m_is_marker);
@@ -1562,16 +1651,16 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
::HIR::ItemPath path(type, trait_name, trait_args);
DEBUG(path);
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods;
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants;
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types;
for(const auto& item : impl.items())
{
::HIR::ItemPath item_path(path, item.name.c_str());
TU_MATCH_DEF(::AST::Item, (*item.data), (e),
(
- BUG(item.data->span, "Unexpected item type in trait impl - " << item.data->tag_str());
+ BUG(item.sp, "Unexpected item type in trait impl - " << item.data->tag_str());
),
(None,
),
@@ -1587,7 +1676,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
} }) );
}
else {
- TODO(item.data->span, "Associated statics in trait impl");
+ TODO(item.sp, "Associated statics in trait impl");
}
),
(Type,
@@ -1596,12 +1685,13 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
),
(Function,
DEBUG("- method " << item.name);
- methods.insert( ::std::make_pair(item.name, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type) }) );
+ methods.insert( ::std::make_pair(item.name, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { item.is_specialisable, LowerHIR_Function(item_path, item.attrs, e, type) }) );
)
)
}
- hir_crate.m_trait_impls.insert( ::std::make_pair(mv$(trait_name), ::HIR::TraitImpl {
+ // Sorted later on
+ hir_crate.m_trait_impls[mv$(trait_name)].generic.push_back(box$(::HIR::TraitImpl {
mv$(params),
mv$(trait_args),
mv$(type),
@@ -1612,7 +1702,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
mv$(types),
LowerHIR_SimplePath(Span(), ast_mod.path())
- }) );
+ }));
}
else if( impl.def().type().m_data.is_None() )
{
@@ -1621,14 +1711,14 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
else
{
auto type = LowerHIR_Type(impl.def().type());
- hir_crate.m_marker_impls.insert( ::std::make_pair( mv$(trait_name), ::HIR::MarkerImpl {
+ hir_crate.m_marker_impls[mv$(trait_name)].generic.push_back(box$(::HIR::MarkerImpl {
mv$(params),
mv$(trait_args),
true,
mv$(type),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } ) );
+ }));
}
}
else
@@ -1637,15 +1727,18 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
auto type = LowerHIR_Type(impl.def().type());
::HIR::ItemPath path(type);
- ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods;
- ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants;
+ auto priv_path = ::HIR::Publicity::new_priv( LowerHIR_SimplePath(Span(), ast_mod.path()) ); // TODO: Does this need to consume anon modules?
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
+ ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods;
+ ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants;
for(const auto& item : impl.items())
{
::HIR::ItemPath item_path(path, item.name.c_str());
TU_MATCH_DEF(::AST::Item, (*item.data), (e),
(
- BUG(item.data->span, "Unexpected item type in inherent impl - " << item.data->tag_str());
+ BUG(item.sp, "Unexpected item type in inherent impl - " << item.data->tag_str());
),
(None,
),
@@ -1653,32 +1746,33 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
),
(Static,
if( e.s_class() == ::AST::Static::CONST ) {
- constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { item.is_pub, item.is_specialisable, ::HIR::Constant {
+ constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { get_pub(item.is_pub), item.is_specialisable, ::HIR::Constant {
::HIR::GenericParams {},
LowerHIR_Type( e.type() ),
LowerHIR_Expr( e.value() )
} }) );
}
else {
- TODO(item.data->span, "Associated statics in inherent impl");
+ TODO(item.sp, "Associated statics in inherent impl");
}
),
(Function,
methods.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> {
- item.is_pub, item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type)
+ get_pub(item.is_pub), item.is_specialisable, LowerHIR_Function(item_path, item.attrs, e, type)
} ) );
)
)
}
- hir_crate.m_type_impls.push_back( ::HIR::TypeImpl {
+ // Sorted later on
+ hir_crate.m_type_impls.generic.push_back( box$(::HIR::TypeImpl {
mv$(params),
mv$(type),
mv$(methods),
mv$(constants),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } );
+ }) );
}
}
for( const auto& i : ast_mod.items() )
@@ -1692,14 +1786,15 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
auto trait_name = mv$(trait.m_path);
auto trait_args = mv$(trait.m_params);
- hir_crate.m_marker_impls.insert( ::std::make_pair( mv$(trait_name), ::HIR::MarkerImpl {
+ // Sorting done later
+ hir_crate.m_marker_impls[mv$(trait_name)].generic.push_back(box$(::HIR::MarkerImpl {
mv$(params),
mv$(trait_args),
false,
mv$(type),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } ) );
+ }) );
}
}
@@ -1735,18 +1830,20 @@ public:
if(crate.m_crate_type != ::AST::Crate::Type::Executable)
{
- rv.m_crate_name = crate.m_crate_name;
if(crate.m_crate_name_suffix != "")
{
- rv.m_crate_name += "-";
- rv.m_crate_name += crate.m_crate_name_suffix;
+ rv.m_crate_name = RcString::new_interned(FMT(crate.m_crate_name + "-" + crate.m_crate_name_suffix));
+ }
+ else
+ {
+ rv.m_crate_name = RcString::new_interned(crate.m_crate_name);
}
}
g_crate_ptr = &rv;
g_ast_crate_ptr = &crate;
g_crate_name = rv.m_crate_name;
- g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : "core");
+ g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : RcString::new_interned("core"));
auto& macros = rv.m_exported_macros;
// - Extract exported macros
@@ -1784,6 +1881,37 @@ public:
auto res = macros.insert( mv$(v) );
DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")");
}
+ else if( v.second->m_rules.empty() ) {
+ // Skip
+ }
+ else {
+ DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\"");
+ it->second = mv$( v.second );
+ }
+ }
+ }
+ for( const auto& mac : crate.m_root_module.m_macro_imports )
+ {
+ if( mac.is_pub )
+ {
+ if( !mac.macro_ptr ) {
+ // Add to the re-export list
+ auto path = ::HIR::SimplePath(mac.path.front(), ::std::vector<RcString>(mac.path.begin()+1, mac.path.end()));;
+ rv.m_proc_macro_reexports.insert( ::std::make_pair( mac.name, ::HIR::Crate::MacroImport { path } ));
+ continue ;
+ }
+ // TODO: Why does this to such a move?
+ auto v = ::std::make_pair( mac.name, MacroRulesPtr(new MacroRules( mv$(*const_cast<MacroRules*>(mac.macro_ptr)) )) );
+
+ auto it = macros.find(mac.name);
+ if( it == macros.end() )
+ {
+ auto res = macros.insert( mv$(v) );
+ DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")");
+ }
+ else if( v.second->m_rules.empty() ) {
+ // Skip
+ }
else {
DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\"");
it->second = mv$( v.second );
@@ -1797,7 +1925,7 @@ public:
for(const auto& ent : crate.m_proc_macros)
{
// Register under an invalid simplepath
- rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath("", { ent.name}), ent.attributes } );
+ rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath(RcString(""), { ent.name }), ent.attributes } );
}
}
else
@@ -1913,25 +2041,28 @@ public:
}
};
// Check for existing defintions of lang items before adding magic ones
- if( rv.m_lang_items.count("boxed_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) ));
- }
- if( rv.m_lang_items.count("placer_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) ));
- }
- if( rv.m_lang_items.count("place_trait") == 0 )
+ if( TARGETVER_1_19 )
{
- rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) ));
- }
- if( rv.m_lang_items.count("box_place_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) ));
- }
- if( rv.m_lang_items.count("in_place_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) ));
+ if( rv.m_lang_items.count("boxed_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) ));
+ }
+ if( rv.m_lang_items.count("placer_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) ));
+ }
+ if( rv.m_lang_items.count("place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) ));
+ }
+ if( rv.m_lang_items.count("box_place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) ));
+ }
+ if( rv.m_lang_items.count("in_place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) ));
+ }
}
}
diff --git a/src/hir/from_ast.hpp b/src/hir/from_ast.hpp
index 4625f479..3eeaaa48 100644
--- a/src/hir/from_ast.hpp
+++ b/src/hir/from_ast.hpp
@@ -16,5 +16,5 @@ extern ::HIR::SimplePath LowerHIR_SimplePath(const Span& sp, const ::AST::Pat
extern ::HIR::TypeRef LowerHIR_Type(const ::TypeRef& ty);
extern ::HIR::Pattern LowerHIR_Pattern(const ::AST::Pattern& pat);
-extern ::std::string g_core_crate;
+extern RcString g_core_crate;
extern ::HIR::Crate* g_crate_ptr;
diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp
index 6daf49c3..baca8d75 100644
--- a/src/hir/from_ast_expr.cpp
+++ b/src/hir/from_ast_expr.cpp
@@ -47,6 +47,9 @@ struct LowerHIR_ExprNode_Visitor:
m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) );
}
+ virtual void visit(::AST::ExprNode_Try& v) override {
+ TODO(v.span(), "Handle _Try");
+ }
virtual void visit(::AST::ExprNode_Macro& v) override {
BUG(v.span(), "Hit ExprNode_Macro");
}
@@ -211,22 +214,28 @@ struct LowerHIR_ExprNode_Visitor:
TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e,
m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(),
- ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.binding().as_Variable().slot )),
+ ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.m_bindings.value.as_Variable().slot )),
mv$(args)
) );
)
else
{
- TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
+ TU_MATCH_DEF(::AST::PathBinding_Value, (v.m_path.m_bindings.value), (e),
(
m_rv.reset( new ::HIR::ExprNode_CallPath( v.span(),
LowerHIR_Path(v.span(), v.m_path),
mv$( args )
) );
),
- (TypeAlias,
- TODO(v.span(), "CallPath -> TupleVariant TypeAlias");
+ (Static,
+ m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(),
+ ::HIR::ExprNodeP(new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC )),
+ mv$(args)
+ ) );
),
+ //(TypeAlias,
+ // TODO(v.span(), "CallPath -> TupleVariant TypeAlias");
+ // ),
(EnumVar,
m_rv.reset( new ::HIR::ExprNode_TupleVariant( v.span(),
LowerHIR_GenericPath(v.span(), v.m_path), false,
@@ -323,16 +332,16 @@ struct LowerHIR_ExprNode_Visitor:
break;
}
- // TODO: Iterate the constructed loop and determine if there are any `break` statements pointing to it
+ // Iterate the constructed loop and determine if there are any `break` statements pointing to it
{
struct LoopVisitor:
public ::HIR::ExprVisitorDef
{
- const ::std::string& top_label;
+ const RcString& top_label;
bool top_is_broken;
- ::std::vector< const ::std::string*> name_stack;
+ ::std::vector< const RcString*> name_stack;
- LoopVisitor(const ::std::string& top_label):
+ LoopVisitor(const RcString& top_label):
top_label(top_label),
top_is_broken(false),
name_stack()
@@ -508,7 +517,7 @@ struct LowerHIR_ExprNode_Visitor:
) );
}
virtual void visit(::AST::ExprNode_StructLiteral& v) override {
- if( v.m_path.binding().is_Union() )
+ if( v.m_path.m_bindings.type.is_Union() )
{
if( v.m_values.size() != 1 )
ERROR(v.span(), E0000, "Union constructors can only specify a single field");
@@ -526,9 +535,10 @@ struct LowerHIR_ExprNode_Visitor:
::HIR::ExprNode_StructLiteral::t_values values;
for(const auto& val : v.m_values)
values.push_back( ::std::make_pair(val.name, LowerHIR_ExprNode_Inner(*val.value)) );
+ // TODO: What if `v.m_path` is an associated type (that's known to be a struct)
m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(),
- LowerHIR_GenericPath(v.span(), v.m_path),
- ! v.m_path.binding().is_EnumVar(),
+ LowerHIR_Path(v.span(), v.m_path),
+ ! v.m_path.m_bindings.type.is_EnumVar(),
LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()),
mv$(values)
) );
@@ -559,22 +569,14 @@ struct LowerHIR_ExprNode_Visitor:
}
virtual void visit(::AST::ExprNode_NamedValue& v) override {
TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e,
- if( !v.m_path.binding().is_Variable() ) {
- BUG(v.span(), "Named value was a local, but wasn't bound - " << v.m_path);
- }
- auto slot = v.m_path.binding().as_Variable().slot;
+ ASSERT_BUG(v.span(), v.m_path.m_bindings.value.is_Variable(), "Named value was a local, but wasn't bound - " << v.m_path);
+ auto slot = v.m_path.m_bindings.value.as_Variable().slot;
m_rv.reset( new ::HIR::ExprNode_Variable( v.span(), e.name, slot ) );
)
- else {
- TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
- (
- auto p = LowerHIR_Path(v.span(), v.m_path);
- if( p.m_data.is_Generic() ) {
- BUG(v.span(), "Unknown binding for PathValue but path is generic - " << v.m_path);
- }
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) );
- ),
- (Struct,
+ else
+ {
+ TU_MATCH_HDRA( (v.m_path.m_bindings.value), {)
+ TU_ARMA(Struct, e) {
ASSERT_BUG(v.span(), e.struct_ || e.hir, "PathValue bound to a struct but pointer not set - " << v.m_path);
// Check the form and emit a PathValue if not a unit
bool is_tuple_constructor = false;
@@ -604,8 +606,8 @@ struct LowerHIR_ExprNode_Visitor:
else {
m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), true ) );
}
- ),
- (EnumVar,
+ }
+ TU_ARMA(EnumVar, e) {
ASSERT_BUG(v.span(), e.enum_ || e.hir, "PathValue bound to an enum but pointer not set - " << v.m_path);
const auto& var_name = v.m_path.nodes().back().name();
bool is_tuple_constructor = false;
@@ -646,11 +648,11 @@ struct LowerHIR_ExprNode_Visitor:
else {
m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false ) );
}
- ),
- (Function,
+ }
+ TU_ARMA(Function, e) {
m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) );
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
if( e.static_ )
{
if( e.static_->s_class() != ::AST::Static::CONST ) {
@@ -669,8 +671,12 @@ struct LowerHIR_ExprNode_Visitor:
{
m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
}
- )
- )
+ }
+ break; default:
+ auto p = LowerHIR_Path(v.span(), v.m_path);
+ ASSERT_BUG(v.span(), !p.m_data.is_Generic(), "Unknown binding for PathValue but path is generic - " << v.m_path);
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) );
+ }
}
}
diff --git a/src/hir/generic_params.cpp b/src/hir/generic_params.cpp
index 381277fc..3f6559a7 100644
--- a/src/hir/generic_params.cpp
+++ b/src/hir/generic_params.cpp
@@ -33,7 +33,7 @@ namespace HIR {
{
os << "<";
for(const auto& lft : x.gp.m_lifetimes) {
- os << "'" << lft << ",";
+ os << "'" << lft.m_name << ",";
}
for(const auto& typ : x.gp.m_types) {
os << typ.m_name;
diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp
index ef83bda7..afa1c682 100644
--- a/src/hir/generic_params.hpp
+++ b/src/hir/generic_params.hpp
@@ -15,19 +15,23 @@ namespace HIR {
struct TypeParamDef
{
- ::std::string m_name;
+ RcString m_name;
::HIR::TypeRef m_default;
bool m_is_sized;
};
+struct LifetimeDef
+{
+ RcString m_name;
+};
TAGGED_UNION(GenericBound, Lifetime,
(Lifetime, struct {
- ::std::string test;
- ::std::string valid_for;
+ LifetimeRef test;
+ LifetimeRef valid_for;
}),
(TypeLifetime, struct {
::HIR::TypeRef type;
- ::std::string valid_for;
+ LifetimeRef valid_for;
}),
(TraitBound, struct {
::HIR::TypeRef type;
@@ -47,8 +51,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x);
class GenericParams
{
public:
- ::std::vector<TypeParamDef> m_types;
- ::std::vector< ::std::string> m_lifetimes;
+ ::std::vector<TypeParamDef> m_types;
+ ::std::vector<LifetimeDef> m_lifetimes;
::std::vector<GenericBound> m_bounds;
diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp
index 5d67ac5f..88b1cb8c 100644
--- a/src/hir/hir.cpp
+++ b/src/hir/hir.cpp
@@ -17,12 +17,29 @@
#include <mir/main_bindings.hpp>
namespace HIR {
+ ::std::ostream& operator<<(::std::ostream& os, const Publicity& x)
+ {
+ if( !x.vis_path ) {
+ os << "pub";
+ }
+ else if( *x.vis_path == *Publicity::none_path ) {
+ os << "priv";
+ }
+ else {
+ os << "pub(" << *x.vis_path << ")";
+ }
+ return os;
+ }
+
::std::ostream& operator<<(::std::ostream& os, const ::HIR::Literal& v)
{
TU_MATCH(::HIR::Literal, (v), (e),
(Invalid,
os << "!";
),
+ (Defer,
+ os << "?";
+ ),
(List,
os << "[";
for(const auto& val : e)
@@ -58,6 +75,8 @@ namespace HIR {
TU_MATCH(::HIR::Literal, (l,r), (le,re),
(Invalid,
),
+ (Defer,
+ ),
(List,
if( le.size() != re.size() )
return false;
@@ -88,9 +107,49 @@ namespace HIR {
)
return true;
}
+
+ ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x) {
+ os << "repr(";
+ switch(x)
+ {
+ case Struct::Repr::Rust: os << "Rust"; break;
+ case Struct::Repr::C: os << "C"; break;
+ case Struct::Repr::Packed: os << "packed"; break;
+ case Struct::Repr::Simd: os << "simd"; break;
+ case Struct::Repr::Aligned: os << "align(?)"; break;
+ case Struct::Repr::Transparent: os << "transparent"; break;
+ }
+ os << ")";
+ return os;
+ }
+}
+
+::std::shared_ptr<::HIR::SimplePath> HIR::Publicity::none_path = ::std::make_shared<HIR::SimplePath>(::HIR::SimplePath{"#", {}});
+
+bool HIR::Publicity::is_visible(const ::HIR::SimplePath& p) const
+{
+ // No path = global public
+ if( !vis_path )
+ return true;
+ // Empty simple path = full private
+ if( *vis_path == *none_path ) {
+ return false;
+ }
+ // Crate names must match
+ if(p.m_crate_name != vis_path->m_crate_name)
+ return false;
+ // `p` must be a child of vis_path
+ if(p.m_components.size() < vis_path->m_components.size())
+ return false;
+ for(size_t i = 0; i < vis_path->m_components.size(); i ++)
+ {
+ if(p.m_components[i] != vis_path->m_components[i])
+ return false;
+ }
+ return true;
}
-size_t HIR::Enum::find_variant(const ::std::string& name) const
+size_t HIR::Enum::find_variant(const RcString& name) const
{
if( m_data.is_Value() )
{
@@ -130,933 +189,6 @@ uint32_t HIR::Enum::get_value(size_t idx) const
}
}
-namespace {
- bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic);
-
- bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
- {
- assert(! left.m_data.is_Infer() );
- const auto& right = (right_in.m_data.is_Infer() || (right_in.m_data.is_Generic() && expand_generic) ? ty_res(right_in) : right_in);
- if( right_in.m_data.is_Generic() )
- expand_generic = false;
-
- //DEBUG("left = " << left << ", right = " << right);
-
- // TODO: What indicates what out of ty_res?
-
- if( const auto* re = right.m_data.opt_Infer() )
- {
- //DEBUG("left = " << left << ", right = " << right);
- switch(re->ty_class)
- {
- case ::HIR::InferClass::None:
- case ::HIR::InferClass::Diverge:
- //return left.m_data.is_Generic();
- return true;
- case ::HIR::InferClass::Integer:
- TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
- return is_integer(le);
- )
- else {
- return left.m_data.is_Generic();
- }
- break;
- case ::HIR::InferClass::Float:
- TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
- return is_float(le);
- )
- else {
- return left.m_data.is_Generic();
- }
- break;
- }
- throw "";
- }
-
- // A local generic could match anything, leave that up to the caller
- if( left.m_data.is_Generic() ) {
- DEBUG("> Generic left, success");
- return true;
- }
- // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match
- if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) {
- // True?
- //DEBUG("> UFCS Unknown left, success");
- return true;
- }
-
- // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
- if( right.m_data.is_Generic() ) {
- // TODO: This is handled above?
- //DEBUG("> Generic right, only if left generic");
- return left.m_data.is_Generic();
- }
- // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
- if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) {
- //DEBUG("> UFCS Unknown right, fuzzy");
- return true;
- }
-
- if( left.m_data.tag() != right.m_data.tag() ) {
- //DEBUG("> Tag mismatch, failure");
- return false;
- }
- TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
- (Infer, assert(!"infer");),
- (Diverge, return true; ),
- (Primitive, return le == re;),
- (Path,
- if( le.path.m_data.tag() != re.path.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre),
- (
- return false;
- ),
- (Generic,
- return matches_genericpath(params, ple, pre, ty_res, expand_generic);
- )
- )
- ),
- (Generic,
- throw "";
- ),
- (TraitObject,
- if( !matches_genericpath(params, le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) )
- return false;
- if( le.m_markers.size() != re.m_markers.size() )
- return false;
- for(unsigned int i = 0; i < le.m_markers.size(); i ++)
- {
- const auto& lm = le.m_markers[i];
- const auto& rm = re.m_markers[i];
- if( !matches_genericpath(params, lm, rm, ty_res, expand_generic) )
- return false;
- }
- return true;
- ),
- (ErasedType,
- throw "Unexpected ErasedType in matches_type_int";
- ),
- (Array,
- if( ! matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic) )
- return false;
- if( le.size_val != re.size_val )
- return false;
- return true;
- ),
- (Slice,
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Tuple,
- if( le.size() != re.size() )
- return false;
- for( unsigned int i = 0; i < le.size(); i ++ )
- if( !matches_type_int(params, le[i], re[i], ty_res, expand_generic) )
- return false;
- return true;
- ),
- (Borrow,
- if( le.type != re.type )
- return false;
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Pointer,
- if( le.type != re.type )
- return false;
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Function,
- if( le.is_unsafe != re.is_unsafe )
- return false;
- if( le.m_abi != re.m_abi )
- return false;
- if( le.m_arg_types.size() != re.m_arg_types.size() )
- return false;
- for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ )
- if( !matches_type_int(params, le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) )
- return false;
- return matches_type_int(params, *le.m_rettype, *re.m_rettype, ty_res, expand_generic);
- ),
- (Closure,
- return le.node == re.node;
- )
- )
- return false;
- }
- bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
- {
- if( left.m_path.m_crate_name != right.m_path.m_crate_name )
- return false;
- if( left.m_path.m_components.size() != right.m_path.m_components.size() )
- return false;
- for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ )
- {
- if( left.m_path.m_components[i] != right.m_path.m_components[i] )
- return false;
- }
-
- if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 )
- {
- // Count mismatch. Allow due to defaults.
- if( left.m_params.m_types.size() != right.m_params.m_types.size() ) {
- return true;
- //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch");
- }
- for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ )
- {
- if( ! matches_type_int(params, left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) )
- return false;
- }
- }
- return true;
- }
-}
-
-//::HIR::TypeRef HIR::Function::make_ty(const Span& sp, const ::HIR::PathParams& params) const
-//{
-// // TODO: Obtain function type for this function (i.e. a type that is specifically for this function)
-// auto fcn_ty_data = ::HIR::FunctionType {
-// m_is_unsafe,
-// m_abi,
-// box$( monomorphise_type(sp, m_params, params, m_return) ),
-// {}
-// };
-// fcn_ty_data.m_arg_types.reserve( m_args.size() );
-// for(const auto& arg : m_args)
-// {
-// fcn_ty_data.m_arg_types.push_back( monomorphise_type(sp, m_params, params, arg.second) );
-// }
-// return ::HIR::TypeRef( mv$(fcn_ty_data) );
-//}
-
-namespace {
- bool is_unbounded_infer(const ::HIR::TypeRef& type) {
- TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e,
- return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge;
- )
- else {
- return false;
- }
- }
-}
-
-bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway
- // TODO: For `Unbound`, it could be valid, if the target is a generic.
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-
-namespace {
-
- struct TypeOrdSpecific_MixedOrdering
- {
- };
-
- ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right);
-
- ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right)
- {
- // TODO: What happens if you get `impl<T> Foo<T> for T` vs `impl<T,U> Foo<U> for T`
-
- // A generic can't be more specific than any other type we can see
- // - It's equally as specific as another Generic, so still false
- if( left.m_data.is_Generic() ) {
- return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess;
- }
- // - A generic is always less specific than anything but itself (handled above)
- if( right.m_data.is_Generic() ) {
- return ::OrdGreater;
- }
-
- TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le),
- (Generic,
- throw "";
- ),
- (Infer,
- BUG(sp, "Hit infer");
- ),
- (Diverge,
- BUG(sp, "Hit diverge");
- ),
- (Closure,
- BUG(sp, "Hit closure");
- ),
- (Primitive,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re,
- if( le != re )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return ::OrdEqual;
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Path,
- if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe),
- (Generic,
- if( lpe.m_path != rpe.m_path )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types);
- ),
- (UfcsUnknown,
- ),
- (UfcsKnown,
- ),
- (UfcsInherent,
- )
- )
- TODO(sp, "Path - " << le.path << " and " << right);
- ),
- (TraitObject,
- ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right);
- const auto& re = right.m_data.as_TraitObject();
- ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right);
- ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right);
-
- auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types);
- if( ord != ::OrdEqual )
- return ord;
- for(size_t i = 0; i < le.m_markers.size(); i ++)
- {
- ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right);
- ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types);
- if(ord != ::OrdEqual)
- return ord;
- }
- return ::OrdEqual;
- ),
- (ErasedType,
- TODO(sp, "ErasedType - " << left);
- ),
- (Function,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Function, re,
- if( left == right )
- return ::OrdEqual;
- TODO(sp, "Function - " << left << " and " << right);
- //return typelist_ord_specific(sp, le.arg_types, re.arg_types);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Tuple,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re,
- return typelist_ord_specific(sp, le, re);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Slice,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re,
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Array,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re,
- if( le.size_val != re.size_val )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Pointer,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re,
- if( le.type != re.type )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Borrow,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re,
- if( le.type != re.type )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- )
- )
- throw "Fell off end of type_ord_specific";
- }
-
- ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re)
- {
- auto rv = ::OrdEqual;
- assert(le.size() == re.size());
- for(unsigned int i = 0; i < le.size(); i ++) {
- auto a = type_ord_specific(sp, le[i], re[i]);
- if( a != ::OrdEqual ) {
- if( rv != ::OrdEqual && a != rv )
- {
- DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]");
- throw TypeOrdSpecific_MixedOrdering {};
- }
- rv = a;
- }
- }
- return rv;
- }
-}
-
-namespace {
- void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait)
- {
- static Span sp;
- assert( cur_trait.m_trait_ptr );
- const auto& tr = *cur_trait.m_trait_ptr;
- auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr);
-
- for(const auto& trait_path_raw : tr.m_all_parent_traits)
- {
- // 1. Monomorph
- auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false);
- // 2. Add
- rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) );
- }
-
- // TODO: Add traits from `Self: Foo` bounds?
- // TODO: Move associated types to the source trait.
- }
- ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds)
- {
- ::std::vector< ::HIR::GenericBound > rv;
- for(const auto& b : bounds)
- {
- TU_MATCHA( (b), (be),
- (Lifetime,
- rv.push_back( ::HIR::GenericBound(be) );
- ),
- (TypeLifetime,
- rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) );
- ),
- (TraitBound,
- rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) );
- add_bound_from_trait(rv, be.type, be.trait);
- ),
- (TypeEquality,
- rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) );
- )
- )
- }
- ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; });
- return rv;
- }
-}
-
-bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const
-{
- static const Span _sp;
- const Span& sp = _sp;
- TRACE_FUNCTION;
- //DEBUG("this = " << *this);
- //DEBUG("other = " << other);
-
- // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules
- // 1. If this->m_type is less specific than other.m_type: return false
- try
- {
- auto ord = type_ord_specific(sp, this->m_type, other.m_type);
- // If `*this` < `other` : false
- if( ord != ::OrdEqual ) {
- DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type);
- return ord == ::OrdGreater;
- }
- // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false
- ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
- if( ord != ::OrdEqual ) {
- DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific");
- return ord == ::OrdGreater;
- }
- }
- catch(const TypeOrdSpecific_MixedOrdering& e)
- {
- BUG(sp, "Mixed ordering in more_specific_than");
- }
-
- //if( other.m_params.m_bounds.size() == 0 ) {
- // DEBUG("- Params (none in other, some in this)");
- // return m_params.m_bounds.size() > 0;
- //}
- // 3. Compare bound set, if there is a rule in oe that is missing from te; return false
- // TODO: Cache these lists (calculate after outer typecheck?)
- auto bounds_t = flatten_bounds(m_params.m_bounds);
- auto bounds_o = flatten_bounds(other.m_params.m_bounds);
-
- DEBUG("bounds_t = " << bounds_t);
- DEBUG("bounds_o = " << bounds_o);
-
- // If there are less bounds in this impl, it can't be more specific.
- if( bounds_t.size() < bounds_o.size() )
- {
- DEBUG("Bound count");
- return false;
- }
-
- auto it_t = bounds_t.begin();
- auto it_o = bounds_o.begin();
- while( it_t != bounds_t.end() && it_o != bounds_o.end() )
- {
- auto cmp = ::ord(*it_t, *it_o);
- if( cmp == OrdEqual )
- {
- ++it_t;
- ++it_o;
- continue ;
- }
-
- // If the two bounds are similar
- if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() )
- {
- const auto& b_t = it_t->as_TraitBound();
- const auto& b_o = it_o->as_TraitBound();
- // Check if the type is equal
- if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path )
- {
- const auto& params_t = b_t.trait.m_path.m_params;
- const auto& params_o = b_o.trait.m_path.m_params;
- switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) )
- {
- case ::OrdLess: return false;
- case ::OrdGreater: return true;
- case ::OrdEqual: break;
- }
- // TODO: Find cases where there's `T: Foo<T>` and `T: Foo<U>`
- for(unsigned int i = 0; i < params_t.m_types.size(); i ++ )
- {
- if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type )
- {
- return true;
- }
- }
- TODO(sp, *it_t << " ?= " << *it_o);
- }
- }
-
- if( cmp == OrdLess )
- {
- ++ it_t;
- }
- else
- {
- //++ it_o;
- return false;
- }
- }
- if( it_t != bounds_t.end() )
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-// Returns `true` if the two impls overlap in the types they will accept
-bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const
-{
- // TODO: Pre-calculate impl trees (with pointers to parent impls)
- struct H {
- static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b)
- {
- for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++)
- {
- if( ! H::types_overlap(a.m_types[i], b.m_types[i]) )
- return false;
- }
- return true;
- }
- static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b)
- {
- static Span sp;
- //DEBUG("(" << a << "," << b << ")");
- if( a.m_data.is_Generic() || b.m_data.is_Generic() )
- return true;
- // TODO: Unbound/Opaque paths?
- if( a.m_data.tag() != b.m_data.tag() )
- return false;
- TU_MATCHA( (a.m_data, b.m_data), (ae, be),
- (Generic,
- ),
- (Infer,
- ),
- (Diverge,
- ),
- (Closure,
- BUG(sp, "Hit closure");
- ),
- (Primitive,
- if( ae != be )
- return false;
- ),
- (Path,
- if( ae.path.m_data.tag() != be.path.m_data.tag() )
- return false;
- TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe),
- (Generic,
- if( ape.m_path != bpe.m_path )
- return false;
- return H::types_overlap(ape.m_params, bpe.m_params);
- ),
- (UfcsUnknown,
- ),
- (UfcsKnown,
- ),
- (UfcsInherent,
- )
- )
- TODO(sp, "Path - " << ae.path << " and " << be.path);
- ),
- (TraitObject,
- if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path )
- return false;
- if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) )
- return false;
- // Marker traits only overlap if the lists are the same (with overlap)
- if( ae.m_markers.size() != be.m_markers.size() )
- return false;
- for(size_t i = 0; i < ae.m_markers.size(); i++)
- {
- if( ae.m_markers[i].m_path != be.m_markers[i].m_path )
- return false;
- if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) )
- return false;
- }
- return true;
- ),
- (ErasedType,
- TODO(sp, "ErasedType - " << a);
- ),
- (Function,
- if( ae.is_unsafe != be.is_unsafe )
- return false;
- if( ae.m_abi != be.m_abi )
- return false;
- if( ae.m_arg_types.size() != be.m_arg_types.size() )
- return false;
- for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++)
- {
- if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) )
- return false;
- }
- ),
- (Tuple,
- if( ae.size() != be.size() )
- return false;
- for(unsigned int i = 0; i < ae.size(); i ++)
- {
- if( ! H::types_overlap(ae[i], be[i]) )
- return false;
- }
- ),
- (Slice,
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Array,
- if( ae.size_val != be.size_val )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Pointer,
- if( ae.type != be.type )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Borrow,
- if( ae.type != be.type )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- )
- )
- return true;
- }
- };
-
- // Quick Check: If the types are equal, they do overlap
- if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args)
- {
- return true;
- }
-
- // 1. Are the impl types of the same form (or is one generic)
- if( ! H::types_overlap(this->m_type, other.m_type) )
- return false;
- if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) )
- return false;
-
- DEBUG("TODO: Handle potential overlap (when not exactly equal)");
- //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args;
- Span sp;
-
- // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false`
- try
- {
- type_ord_specific(sp, this->m_type, other.m_type);
- typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
- }
- catch(const TypeOrdSpecific_MixedOrdering& /*e*/)
- {
- return false;
- }
-
- // TODO: Detect `impl<T> Foo<T> for Bar<T>` vs `impl<T> Foo<&T> for Bar<T>`
- // > Create values for impl params from the type, then check if the trait params are compatible
- // > Requires two lists, and telling which one to use by the end
- auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
- bool is_reversed = false;
- ::std::vector<const ::HIR::TypeRef*> impl_tys;
- auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
- assert(idx < impl_tys.size());
- if( impl_tys.at(idx) )
- {
- DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
- return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
- }
- else
- {
- impl_tys.at(idx) = &x;
- return ::HIR::Compare::Equal;
- }
- };
- impl_tys.resize( this->m_params.m_types.size() );
- if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch, try other ordering");
- is_reversed = true;
- impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
- if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch in both orderings");
- return false;
- }
- if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Params mismatch");
- return false;
- }
- // Matched with second ording
- }
- else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Param mismatch, try other ordering");
- is_reversed = true;
- impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
- if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch in alt ordering");
- return false;
- }
- if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Params mismatch in alt ordering");
- return false;
- }
- // Matched with second ordering
- }
- else
- {
- // Matched with first ordering
- }
-
- struct H2 {
- static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TypeRef& tmp)
- {
- if( ! monomorphise_type_needed(in_ty) ) {
- return in_ty;
- }
- else if( const auto* tep = in_ty.m_data.opt_Generic() ) {
- ASSERT_BUG(sp, tep->binding < args.size(), "");
- ASSERT_BUG(sp, args[tep->binding], "");
- return *args[tep->binding];
- }
- else {
- auto monomorph_cb = [&](const auto& t)->const auto& {
- const auto& te = t.m_data.as_Generic();
- assert(te.binding < args.size());
- ASSERT_BUG(sp, te.binding < args.size(), "");
- ASSERT_BUG(sp, args[te.binding], "");
- return *args[te.binding];
- };
- tmp = monomorphise_type_with(sp, in_ty, monomorph_cb);
- // TODO: EAT?
- return tmp;
- }
- }
- static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TraitPath& tmp)
- {
- if( ! monomorphise_traitpath_needed(in) ) {
- return in;
- }
- else {
- auto monomorph_cb = [&](const auto& t)->const auto& {
- const auto& te = t.m_data.as_Generic();
- assert(te.binding < args.size());
- ASSERT_BUG(sp, te.binding < args.size(), "");
- ASSERT_BUG(sp, args[te.binding], "");
- return *args[te.binding];
- };
- tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true);
- // TODO: EAT?
- return tmp;
- }
- }
- static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector<const ::HIR::TypeRef*>& args, const ::HIR::TraitImpl& g_src)
- {
- TRACE_FUNCTION;
- static Span sp;
- for(const auto& tb : id.m_params.m_bounds)
- {
- if(tb.is_TraitBound())
- {
- ::HIR::TypeRef tmp_ty;
- ::HIR::TraitPath tmp_tp;
- const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty);
- const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);;
-
- // Determine if `ty` would be bounded (it's an ATY or generic)
- if( ty.m_data.is_Generic() ) {
- bool found = false;
- for(const auto& bound : g_src.m_params.m_bounds)
- {
- if(const auto* be = bound.opt_TraitBound())
- {
- if( be->type != ty ) continue;
- if( be->trait != trait ) continue;
- found = true;
- }
- }
- if( !found )
- {
- DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds());
- return false;
- }
- }
- else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) {
- TODO(Span(), "Check bound " << ty << " : " << trait << " in source bounds or trait bounds");
- }
- else {
- // Search the crate for an impl
- bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool {
- DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds());
-
- ::std::vector<const ::HIR::TypeRef*> impl_tys { ti.m_params.m_types.size() };
- auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
- auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
- assert(idx < impl_tys.size());
- if( impl_tys.at(idx) )
- {
- DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
- return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
- }
- else
- {
- impl_tys.at(idx) = &x;
- return ::HIR::Compare::Equal;
- }
- };
- // 1. Triple-check the type matches (and get generics)
- if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) )
- return false;
- // 2. Check trait params
- assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size());
- for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++)
- {
- if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) )
- return false;
- }
- // 3. Check bounds on the impl
- if( !H2::check_bounds(crate, ti, impl_tys, g_src) )
- return false;
- // 4. Check ATY bounds on the trait path
- for(const auto& atyb : trait.m_type_bounds)
- {
- const auto& aty = ti.m_types.at(atyb.first);
- if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) )
- return false;
- }
- // All those pass? It's good.
- return true;
- });
- if( !rv )
- {
- return false;
- }
- }
- }
- else
- {
- // TODO: Other bound types?
- }
- }
- // No bounds failed, it's good
- return true;
- }
- };
-
- // The two impls could overlap, pending on trait bounds
- if(is_reversed)
- {
- DEBUG("(reversed) impl params " << FMT_CB(os,
- for(auto* p : impl_tys)
- {
- if(p)
- os << *p;
- else
- os << "?";
- os << ",";
- }
- ));
- // Check bounds on `other` using these params
- // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result?
- return H2::check_bounds(crate, other, impl_tys, *this);
- }
- else
- {
- DEBUG("impl params " << FMT_CB(os,
- for(auto* p : impl_tys)
- {
- if(p)
- os << *p;
- else
- os << "?";
- os << ",";
- }
- ));
- // Check bounds on `*this`
- return H2::check_bounds(crate, *this, impl_tys, other);
- }
-}
-
const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path(const Span& sp, const char* name) const
{
@@ -1229,122 +361,3 @@ const ::HIR::Function& ::HIR::Crate::get_function_by_path(const Span& sp, const
}
}
-bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const
-{
- auto its = this->m_trait_impls.equal_range( trait );
- for( auto it = its.first; it != its.second; ++ it )
- {
- const auto& impl = it->second;
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- if( ec.second.m_data->find_trait_impls(trait, type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const
-{
- auto its = this->m_marker_impls.equal_range( trait );
- for( auto it = its.first; it != its.second; ++ it )
- {
- const auto& impl = it->second;
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- if( ec.second.m_data->find_auto_trait_impls(trait, type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const
-{
- // TODO: Restrict which crate is searched based on the type.
- for( const auto& impl : this->m_type_impls )
- {
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- //DEBUG("- " << ec.first);
- if( ec.second.m_data->find_type_impls(type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-
-const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const
-{
- if( !ep )
- {
- return &*ep.m_mir;
- }
- else
- {
- if( !ep.m_mir )
- {
- ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip);
-
- auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep);
-
- // Ensure typechecked
- if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck )
- {
- if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest )
- ERROR(Span(), E0000, "Loop in constant evaluation");
- ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest;
-
- // TODO: Set debug/timing stage
- //Debug_SetStagePre("HIR Typecheck");
- // - Can store that on the Expr, OR get it from the item path
- typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) };
- ms.m_impl_generics = ep.m_state->m_impl_generics;
- ms.m_item_generics = ep.m_state->m_item_generics;
- ms.m_traits = ep.m_state->m_traits;
- Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut);
- //Debug_SetStagePre("Expand HIR Annotate");
- HIR_Expand_AnnotateUsage_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Closures");
- HIR_Expand_Closures_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Calls");
- HIR_Expand_UfcsEverything_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Reborrows");
- HIR_Expand_Reborrows_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR ErasedType");
- //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe?
- //Typecheck_Expressions_Validate(*hir_crate);
-
- ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
- }
- // Generate MIR
- if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir )
- {
- if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest )
- ERROR(Span(), E0000, "Loop in constant evaluation");
- ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest;
- //Debug_SetStage("Lower MIR");
- HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty);
- ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
- }
- assert(ep.m_mir);
- }
- return &*ep.m_mir;
- }
-}
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index 8024e1c0..8b718b4f 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>
@@ -37,13 +38,50 @@ class Static;
class ValueItem;
class TypeItem;
+class MacroItem;
class ItemPath;
+class Publicity
+{
+ static ::std::shared_ptr<::HIR::SimplePath> none_path;
+ ::std::shared_ptr<::HIR::SimplePath> vis_path;
+
+ Publicity(::std::shared_ptr<::HIR::SimplePath> p)
+ :vis_path(p)
+ {
+ }
+public:
+
+ static Publicity new_global() {
+ return Publicity({});
+ }
+ static Publicity new_none() {
+ return Publicity(none_path);
+ }
+ static Publicity new_priv(::HIR::SimplePath p) {
+ return Publicity(::std::make_shared<HIR::SimplePath>(::std::move(p)));
+ }
+
+ bool is_global() const {
+ return !vis_path;
+ }
+ bool is_visible(const ::HIR::SimplePath& p) const;
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const Publicity& x);
+};
+
+enum class ConstEvalState
+{
+ None,
+ Active,
+ Complete,
+};
+
template<typename Ent>
struct VisEnt
{
- bool is_public;
+ Publicity publicity;
Ent ent;
};
@@ -51,6 +89,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
@@ -111,6 +150,9 @@ public:
TypeRef m_type;
ExprPtr m_value;
Literal m_value_res;
+
+ // A cache of monomorphised versions when the `const` depends on generics for its value
+ mutable ::std::map< ::HIR::Path, Literal> m_monomorph_cache;
};
class Function
{
@@ -124,6 +166,7 @@ public:
//PointerMut,
//PointerConst,
Box,
+ Custom,
};
typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t;
@@ -157,7 +200,7 @@ struct TypeAlias
};
typedef ::std::vector< VisEnt<::HIR::TypeRef> > t_tuple_fields;
-typedef ::std::vector< ::std::pair< ::std::string, VisEnt<::HIR::TypeRef> > > t_struct_fields;
+typedef ::std::vector< ::std::pair< RcString, VisEnt<::HIR::TypeRef> > > t_struct_fields;
/// Cache of the state of various language traits on an enum/struct
struct TraitMarkings
@@ -212,11 +255,18 @@ struct StructMarkings
unsigned int coerce_param = ~0u;
};
+class ExternType
+{
+public:
+ // TODO: do extern types need any associated data?
+ TraitMarkings m_markings;
+};
+
class Enum
{
public:
struct DataVariant {
- ::std::string name;
+ RcString name;
bool is_struct; // Indicates that the variant does not show up in the value namespace
::HIR::TypeRef type;
};
@@ -227,7 +277,7 @@ public:
Usize, U8, U16, U32, U64,
};
struct ValueVariant {
- ::std::string name;
+ RcString name;
::HIR::ExprPtr expr;
// TODO: Signed.
uint64_t val;
@@ -248,7 +298,7 @@ public:
size_t num_variants() const {
return (m_data.is_Data() ? m_data.as_Data().size() : m_data.as_Value().variants.size());
}
- size_t find_variant(const ::std::string& ) const;
+ size_t find_variant(const RcString& ) const;
/// Returns true if this enum is a C-like enum (has values only)
bool is_value() const;
@@ -264,6 +314,8 @@ public:
C,
Packed,
Simd,
+ Aligned, // Alignment stored elsewhere
+ Transparent,
};
TAGGED_UNION(Data, Unit,
(Unit, struct {}),
@@ -271,13 +323,33 @@ public:
(Named, t_struct_fields)
);
+ Struct(GenericParams params, Repr repr, Data data)
+ :m_params(mv$(params))
+ ,m_repr(mv$(repr))
+ ,m_data(mv$(data))
+ {
+ }
+ Struct(GenericParams params, Repr repr, Data data, unsigned align, TraitMarkings tm, StructMarkings sm)
+ :m_params(mv$(params))
+ ,m_repr(mv$(repr))
+ ,m_data(mv$(data))
+ ,m_forced_alignment(align)
+ ,m_markings(mv$(tm))
+ ,m_struct_markings(mv$(sm))
+ {
+ }
+
GenericParams m_params;
Repr m_repr;
Data m_data;
+ unsigned m_forced_alignment = 0;
TraitMarkings m_markings;
StructMarkings m_struct_markings;
+
+ ConstEvalState const_eval_state = ConstEvalState::None;
};
+extern ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x);
class Union
{
public:
@@ -297,7 +369,7 @@ public:
struct AssociatedType
{
bool is_sized;
- ::std::string m_lifetime_bound;
+ LifetimeRef m_lifetime_bound;
::std::vector< ::HIR::TraitPath> m_trait_bounds;
::HIR::TypeRef m_default;
};
@@ -310,23 +382,25 @@ class Trait
{
public:
GenericParams m_params;
- ::std::string m_lifetime;
+ LifetimeRef m_lifetime;
::std::vector< ::HIR::TraitPath > m_parent_traits;
bool m_is_marker; // aka OIBIT
- ::std::unordered_map< ::std::string, AssociatedType > m_types;
- ::std::unordered_map< ::std::string, TraitValueItem > m_values;
+ ::std::unordered_map< RcString, AssociatedType > m_types;
+ ::std::unordered_map< RcString, TraitValueItem > m_values;
// Indexes into the vtable for each present method and value
- ::std::unordered_multimap< ::std::string, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes;
+ ::std::unordered_multimap< RcString, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes;
// Indexes in the vtable parameter list for each associated type
- ::std::unordered_map< ::std::string, unsigned int > m_type_indexes;
+ ::std::unordered_map< RcString, unsigned int > m_type_indexes;
// Flattend set of parent traits (monomorphised and associated types fixed)
::std::vector< ::HIR::TraitPath > m_all_parent_traits;
+ // VTable path
+ ::HIR::SimplePath m_vtable_path;
- Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::TraitPath> parents):
+ Trait( GenericParams gps, LifetimeRef lifetime, ::std::vector< ::HIR::TraitPath> parents):
m_params( mv$(gps) ),
m_lifetime( mv$(lifetime) ),
m_parent_traits( mv$(parents) ),
@@ -334,6 +408,17 @@ public:
{}
};
+class ProcMacro
+{
+public:
+ // Name of the macro
+ RcString name;
+ // Path to the handler
+ ::HIR::SimplePath path;
+ // A list of attributes to hand to the handler
+ ::std::vector<::std::string> attributes;
+};
+
class Module
{
public:
@@ -341,11 +426,13 @@ public:
::std::vector< ::HIR::SimplePath> m_traits;
// Contains all values and functions (including type constructors)
- ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<ValueItem>> > m_value_items;
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<ValueItem>> > m_value_items;
// Contains types, traits, and modules
- ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items;
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items;
+ // Macros!
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<MacroItem>> > m_macro_items;
- ::std::vector< ::std::pair<::std::string, Static> > m_inline_statics;
+ ::std::vector< ::std::pair<RcString, Static> > m_inline_statics;
Module() {}
Module(const Module&) = delete;
@@ -360,6 +447,7 @@ TAGGED_UNION(TypeItem, Import,
(Import, struct { ::HIR::SimplePath path; bool is_variant; unsigned int idx; }),
(Module, Module),
(TypeAlias, TypeAlias), // NOTE: These don't introduce new values
+ (ExternType, ExternType),
(Enum, Enum),
(Struct, Struct),
(Union, Union),
@@ -373,6 +461,11 @@ TAGGED_UNION(ValueItem, Import,
(Function, Function),
(StructConstructor, struct { ::HIR::SimplePath ty; })
);
+TAGGED_UNION(MacroItem, Import,
+ (Import, struct { ::HIR::SimplePath path; }),
+ (MacroRules, MacroRulesPtr),
+ (ProcMacro, ProcMacro)
+ );
// --------------------------------------------------------------------
@@ -381,7 +474,7 @@ class TypeImpl
public:
template<typename T>
struct VisImplEnt {
- bool is_pub;
+ Publicity publicity;
bool is_specialisable;
T data;
};
@@ -389,8 +482,8 @@ public:
::HIR::GenericParams m_params;
::HIR::TypeRef m_type;
- ::std::map< ::std::string, VisImplEnt< ::HIR::Function> > m_methods;
- ::std::map< ::std::string, VisImplEnt< ::HIR::Constant> > m_constants;
+ ::std::map< RcString, VisImplEnt< ::HIR::Function> > m_methods;
+ ::std::map< RcString, VisImplEnt< ::HIR::Constant> > m_constants;
::HIR::SimplePath m_src_module;
@@ -413,11 +506,11 @@ public:
::HIR::PathParams m_trait_args;
::HIR::TypeRef m_type;
- ::std::map< ::std::string, ImplEnt< ::HIR::Function> > m_methods;
- ::std::map< ::std::string, ImplEnt< ::HIR::Constant> > m_constants;
- ::std::map< ::std::string, ImplEnt< ::HIR::Static> > m_statics;
+ ::std::map< RcString, ImplEnt< ::HIR::Function> > m_methods;
+ ::std::map< RcString, ImplEnt< ::HIR::Constant> > m_constants;
+ ::std::map< RcString, ImplEnt< ::HIR::Static> > m_statics;
- ::std::map< ::std::string, ImplEnt< ::HIR::TypeRef> > m_types;
+ ::std::map< RcString, ImplEnt< ::HIR::TypeRef> > m_types;
::HIR::SimplePath m_src_module;
@@ -461,31 +554,63 @@ class ExternLibrary
public:
::std::string name;
};
-class ProcMacro
-{
-public:
- // Name of the macro
- ::std::string name;
- // Path to the handler
- ::HIR::SimplePath path;
- // A list of attributes to hand to the handler
- ::std::vector<::std::string> attributes;
-};
class Crate
{
public:
- ::std::string m_crate_name;
+ RcString m_crate_name;
Module m_root_module;
- /// Impl blocks on just a type
- ::std::vector< ::HIR::TypeImpl > m_type_impls;
+ template<typename T>
+ struct ImplGroup
+ {
+ typedef ::std::vector<::std::unique_ptr<T>> list_t;
+ ::std::map<::HIR::SimplePath, list_t> named;
+ list_t non_named; // TODO: use a map of HIR::TypeRef::Data::Tag
+ list_t generic;
+
+ const list_t* get_list_for_type(const ::HIR::TypeRef& ty) const {
+ static list_t empty;
+ if( const auto* p = ty.get_sort_path() ) {
+ auto it = named.find(*p);
+ if( it != named.end() )
+ return &it->second;
+ else
+ return nullptr;
+ }
+ else {
+ // TODO: Sort these by type tag, use the `Primitive` group if `ty` is Infer
+ return &non_named;
+ }
+ }
+ list_t& get_list_for_type_mut(const ::HIR::TypeRef& ty) {
+ if( const auto* p = ty.get_sort_path() ) {
+ return named[*p];
+ }
+ else {
+ // TODO: Ivars match with core types
+ return non_named;
+ }
+ }
+ };
+ /// Impl blocks on just a type, split into three groups
+ // - Named type (sorted on the path)
+ // - Primitive types
+ // - Unsorted (generics, and everything before outer type resolution)
+ ImplGroup<::HIR::TypeImpl> m_type_impls;
+
/// Impl blocks
- ::std::multimap< ::HIR::SimplePath, ::HIR::TraitImpl > m_trait_impls;
- ::std::multimap< ::HIR::SimplePath, ::HIR::MarkerImpl > m_marker_impls;
+ ::std::map< ::HIR::SimplePath, ImplGroup<::HIR::TraitImpl> > m_trait_impls;
+ ::std::map< ::HIR::SimplePath, ImplGroup<::HIR::MarkerImpl> > m_marker_impls;
/// Macros exported by this crate
- ::std::unordered_map< ::std::string, ::MacroRulesPtr > m_exported_macros;
+ ::std::unordered_map< RcString, ::MacroRulesPtr > m_exported_macros;
+ /// Macros re-exported by this crate
+ struct MacroImport {
+ ::HIR::SimplePath path;
+ //bool is_proc_macro;
+ };
+ ::std::unordered_map< RcString, MacroImport > m_proc_macro_reexports;
/// Procedural macros presented
::std::vector< ::HIR::ProcMacro> m_proc_macros;
@@ -493,7 +618,7 @@ public:
::std::unordered_map< ::std::string, ::HIR::SimplePath> m_lang_items;
/// Referenced crates
- ::std::unordered_map< ::std::string, ExternCrate> m_ext_crates;
+ ::std::unordered_map< RcString, ExternCrate> m_ext_crates;
/// Referenced system libraries
::std::vector<ExternLibrary> m_ext_libs;
/// Extra paths for the linker
@@ -501,7 +626,7 @@ public:
/// Method called to populate runtime state after deserialisation
/// See hir/crate_post_load.cpp
- void post_load_update(const ::std::string& loaded_name);
+ void post_load_update(const RcString& loaded_name);
const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const;
const ::HIR::SimplePath& get_lang_item_path_opt(const char* name) const;
diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp
new file mode 100644
index 00000000..3a33d5cb
--- /dev/null
+++ b/src/hir/hir_ops.cpp
@@ -0,0 +1,1148 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir/hir_ops.cpp
+ * - Complex operations on the HIR
+ */
+#include "hir.hpp"
+#include <algorithm>
+#include <hir_typeck/common.hpp>
+#include <hir_typeck/expr_visit.hpp> // for invoking typecheck
+#include "item_path.hpp"
+#include "expr_state.hpp"
+#include <hir_conv/main_bindings.hpp>
+#include <hir_expand/main_bindings.hpp>
+#include <mir/main_bindings.hpp>
+
+namespace {
+ bool matches_genericpath(const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic);
+
+ bool matches_type_int(const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
+ {
+ assert(! left.m_data.is_Infer() );
+ const auto& right = (right_in.m_data.is_Infer() ? ty_res(right_in) : right_in);
+ if( right_in.m_data.is_Generic() )
+ expand_generic = false;
+
+ //DEBUG("left = " << left << ", right = " << right);
+
+ // TODO: What indicates what out of ty_res?
+
+ if( const auto* re = right.m_data.opt_Infer() )
+ {
+ //DEBUG("left = " << left << ", right = " << right);
+ switch(re->ty_class)
+ {
+ case ::HIR::InferClass::None:
+ case ::HIR::InferClass::Diverge:
+ //return left.m_data.is_Generic();
+ return true;
+ case ::HIR::InferClass::Integer:
+ TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
+ return is_integer(le);
+ )
+ else {
+ return left.m_data.is_Generic();
+ }
+ break;
+ case ::HIR::InferClass::Float:
+ TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
+ return is_float(le);
+ )
+ else {
+ return left.m_data.is_Generic();
+ }
+ break;
+ }
+ throw "";
+ }
+
+ // A local generic could match anything, leave that up to the caller
+ if( left.m_data.is_Generic() ) {
+ DEBUG("> Generic left, success");
+ return true;
+ }
+ // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match
+ if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) {
+ // True?
+ //DEBUG("> UFCS Unknown left, success");
+ return true;
+ }
+
+ // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
+ if( right.m_data.is_Generic() ) {
+ // TODO: This is handled above?
+ //DEBUG("> Generic right, only if left generic");
+ return left.m_data.is_Generic();
+ }
+ // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
+ if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) {
+ //DEBUG("> UFCS Unknown right, fuzzy");
+ return true;
+ }
+
+ if( left.m_data.tag() != right.m_data.tag() ) {
+ //DEBUG("> Tag mismatch, failure");
+ return false;
+ }
+ TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
+ (Infer, assert(!"infer");),
+ (Diverge, return true; ),
+ (Primitive, return le == re;),
+ (Path,
+ if( le.path.m_data.tag() != re.path.m_data.tag() )
+ return false;
+ TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre),
+ (
+ return false;
+ ),
+ (Generic,
+ return matches_genericpath( ple, pre, ty_res, expand_generic);
+ )
+ )
+ ),
+ (Generic,
+ throw "";
+ ),
+ (TraitObject,
+ if( !matches_genericpath(le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) )
+ return false;
+ if( le.m_markers.size() != re.m_markers.size() )
+ return false;
+ for(unsigned int i = 0; i < le.m_markers.size(); i ++)
+ {
+ const auto& lm = le.m_markers[i];
+ const auto& rm = re.m_markers[i];
+ if( !matches_genericpath(lm, rm, ty_res, expand_generic) )
+ return false;
+ }
+ return true;
+ ),
+ (ErasedType,
+ throw "Unexpected ErasedType in matches_type_int";
+ ),
+ (Array,
+ if( ! matches_type_int(*le.inner, *re.inner, ty_res, expand_generic) )
+ return false;
+ if( le.size_val != re.size_val )
+ return false;
+ return true;
+ ),
+ (Slice,
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Tuple,
+ if( le.size() != re.size() )
+ return false;
+ for( unsigned int i = 0; i < le.size(); i ++ )
+ if( !matches_type_int(le[i], re[i], ty_res, expand_generic) )
+ return false;
+ return true;
+ ),
+ (Borrow,
+ if( le.type != re.type )
+ return false;
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Pointer,
+ if( le.type != re.type )
+ return false;
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Function,
+ if( le.is_unsafe != re.is_unsafe )
+ return false;
+ if( le.m_abi != re.m_abi )
+ return false;
+ if( le.m_arg_types.size() != re.m_arg_types.size() )
+ return false;
+ for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ )
+ if( !matches_type_int(le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) )
+ return false;
+ return matches_type_int(*le.m_rettype, *re.m_rettype, ty_res, expand_generic);
+ ),
+ (Closure,
+ return le.node == re.node;
+ )
+ )
+ return false;
+ }
+ bool matches_genericpath(const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
+ {
+ if( left.m_path.m_crate_name != right.m_path.m_crate_name )
+ return false;
+ if( left.m_path.m_components.size() != right.m_path.m_components.size() )
+ return false;
+ for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ )
+ {
+ if( left.m_path.m_components[i] != right.m_path.m_components[i] )
+ return false;
+ }
+
+ if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 )
+ {
+ // Count mismatch. Allow due to defaults.
+ if( left.m_params.m_types.size() != right.m_params.m_types.size() ) {
+ return true;
+ //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch");
+ }
+ for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ )
+ {
+ if( ! matches_type_int(left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) )
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+namespace {
+ bool is_unbounded_infer(const ::HIR::TypeRef& type) {
+ if( const auto* e = type.m_data.opt_Infer() ) {
+ return e->ty_class == ::HIR::InferClass::None || e->ty_class == ::HIR::InferClass::Diverge;
+ }
+ else {
+ return false;
+ }
+ }
+}
+
+bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway
+ // TODO: For `Unbound`, it could be valid, if the target is a generic.
+ // - Pure infer could also be useful (for knowing if there's any other potential impls)
+
+ // TODO: Allow unbounded types iff there's some non-unbounded parameters?
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+
+namespace {
+
+ struct TypeOrdSpecific_MixedOrdering
+ {
+ };
+
+ ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right);
+
+ ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right)
+ {
+ // TODO: What happens if you get `impl<T> Foo<T> for T` vs `impl<T,U> Foo<U> for T`
+
+ // A generic can't be more specific than any other type we can see
+ // - It's equally as specific as another Generic, so still false
+ if( left.m_data.is_Generic() ) {
+ return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess;
+ }
+ // - A generic is always less specific than anything but itself (handled above)
+ if( right.m_data.is_Generic() ) {
+ return ::OrdGreater;
+ }
+
+ if( left == right ) {
+ return ::OrdEqual;
+ }
+
+ TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le),
+ (Generic,
+ throw "";
+ ),
+ (Infer,
+ BUG(sp, "Hit infer");
+ ),
+ (Diverge,
+ BUG(sp, "Hit diverge");
+ ),
+ (Closure,
+ BUG(sp, "Hit closure");
+ ),
+ (Primitive,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re,
+ if( le != re )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return ::OrdEqual;
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Path,
+ if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe),
+ (Generic,
+ if( lpe.m_path != rpe.m_path )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types);
+ ),
+ (UfcsUnknown,
+ ),
+ (UfcsKnown,
+ ),
+ (UfcsInherent,
+ )
+ )
+ TODO(sp, "Path - " << le.path << " and " << right);
+ ),
+ (TraitObject,
+ ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right);
+ const auto& re = right.m_data.as_TraitObject();
+ ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right);
+ ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right);
+
+ auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types);
+ if( ord != ::OrdEqual )
+ return ord;
+ for(size_t i = 0; i < le.m_markers.size(); i ++)
+ {
+ ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right);
+ ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types);
+ if(ord != ::OrdEqual)
+ return ord;
+ }
+ return ::OrdEqual;
+ ),
+ (ErasedType,
+ TODO(sp, "ErasedType - " << left);
+ ),
+ (Function,
+ if(/*const auto* re =*/ right.m_data.opt_Function() ) {
+ if( left == right )
+ return ::OrdEqual;
+ TODO(sp, "Function - " << left << " vs " << right);
+ //return typelist_ord_specific(sp, le.arg_types, re->arg_types);
+ }
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Tuple,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re,
+ return typelist_ord_specific(sp, le, re);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Slice,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re,
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Array,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re,
+ if( le.size_val != re.size_val )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Pointer,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re,
+ if( le.type != re.type )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Borrow,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re,
+ if( le.type != re.type )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ )
+ )
+ throw "Fell off end of type_ord_specific";
+ }
+
+ ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re)
+ {
+ auto rv = ::OrdEqual;
+ assert(le.size() == re.size());
+ for(unsigned int i = 0; i < le.size(); i ++) {
+ auto a = type_ord_specific(sp, le[i], re[i]);
+ if( a != ::OrdEqual ) {
+ if( rv != ::OrdEqual && a != rv )
+ {
+ DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]");
+ throw TypeOrdSpecific_MixedOrdering {};
+ }
+ rv = a;
+ }
+ }
+ return rv;
+ }
+}
+
+namespace {
+ void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait)
+ {
+ static Span sp;
+ assert( cur_trait.m_trait_ptr );
+ const auto& tr = *cur_trait.m_trait_ptr;
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr);
+
+ for(const auto& trait_path_raw : tr.m_all_parent_traits)
+ {
+ // 1. Monomorph
+ auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false);
+ // 2. Add
+ rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) );
+ }
+
+ // TODO: Add traits from `Self: Foo` bounds?
+ // TODO: Move associated types to the source trait.
+ }
+ ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds)
+ {
+ ::std::vector< ::HIR::GenericBound > rv;
+ for(const auto& b : bounds)
+ {
+ TU_MATCHA( (b), (be),
+ (Lifetime,
+ rv.push_back( ::HIR::GenericBound(be) );
+ ),
+ (TypeLifetime,
+ rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) );
+ ),
+ (TraitBound,
+ rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) );
+ add_bound_from_trait(rv, be.type, be.trait);
+ ),
+ (TypeEquality,
+ rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) );
+ )
+ )
+ }
+ ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; });
+ return rv;
+ }
+}
+
+bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const
+{
+ static const Span _sp;
+ const Span& sp = _sp;
+ TRACE_FUNCTION;
+ //DEBUG("this = " << *this);
+ //DEBUG("other = " << other);
+
+ // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules
+ // 1. If this->m_type is less specific than other.m_type: return false
+ try
+ {
+ auto ord = type_ord_specific(sp, this->m_type, other.m_type);
+ // If `*this` < `other` : false
+ if( ord != ::OrdEqual ) {
+ DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type);
+ return ord == ::OrdGreater;
+ }
+ // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false
+ ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
+ if( ord != ::OrdEqual ) {
+ DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific");
+ return ord == ::OrdGreater;
+ }
+ }
+ catch(const TypeOrdSpecific_MixedOrdering& e)
+ {
+ BUG(sp, "Mixed ordering in more_specific_than");
+ }
+
+ //if( other.m_params.m_bounds.size() == 0 ) {
+ // DEBUG("- Params (none in other, some in this)");
+ // return m_params.m_bounds.size() > 0;
+ //}
+ // 3. Compare bound set, if there is a rule in oe that is missing from te; return false
+ // TODO: Cache these lists (calculate after outer typecheck?)
+ auto bounds_t = flatten_bounds(m_params.m_bounds);
+ auto bounds_o = flatten_bounds(other.m_params.m_bounds);
+
+ DEBUG("bounds_t = " << bounds_t);
+ DEBUG("bounds_o = " << bounds_o);
+
+ // If there are less bounds in this impl, it can't be more specific.
+ if( bounds_t.size() < bounds_o.size() )
+ {
+ DEBUG("Bound count");
+ return false;
+ }
+
+ auto it_t = bounds_t.begin();
+ auto it_o = bounds_o.begin();
+ while( it_t != bounds_t.end() && it_o != bounds_o.end() )
+ {
+ auto cmp = ::ord(*it_t, *it_o);
+ if( cmp == OrdEqual )
+ {
+ ++it_t;
+ ++it_o;
+ continue ;
+ }
+
+ // If the two bounds are similar
+ if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() )
+ {
+ const auto& b_t = it_t->as_TraitBound();
+ const auto& b_o = it_o->as_TraitBound();
+ // Check if the type is equal
+ if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path )
+ {
+ const auto& params_t = b_t.trait.m_path.m_params;
+ const auto& params_o = b_o.trait.m_path.m_params;
+ switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) )
+ {
+ case ::OrdLess: return false;
+ case ::OrdGreater: return true;
+ case ::OrdEqual: break;
+ }
+ // TODO: Find cases where there's `T: Foo<T>` and `T: Foo<U>`
+ for(unsigned int i = 0; i < params_t.m_types.size(); i ++ )
+ {
+ if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type )
+ {
+ return true;
+ }
+ }
+ TODO(sp, *it_t << " ?= " << *it_o);
+ }
+ }
+
+ if( cmp == OrdLess )
+ {
+ ++ it_t;
+ }
+ else
+ {
+ //++ it_o;
+ return false;
+ }
+ }
+ if( it_t != bounds_t.end() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Returns `true` if the two impls overlap in the types they will accept
+bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const
+{
+ // TODO: Pre-calculate impl trees (with pointers to parent impls)
+ struct H {
+ static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b)
+ {
+ for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++)
+ {
+ if( ! H::types_overlap(a.m_types[i], b.m_types[i]) )
+ return false;
+ }
+ return true;
+ }
+ static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b)
+ {
+ static Span sp;
+ //DEBUG("(" << a << "," << b << ")");
+ if( a.m_data.is_Generic() || b.m_data.is_Generic() )
+ return true;
+ // TODO: Unbound/Opaque paths?
+ if( a.m_data.tag() != b.m_data.tag() )
+ return false;
+ TU_MATCHA( (a.m_data, b.m_data), (ae, be),
+ (Generic,
+ ),
+ (Infer,
+ ),
+ (Diverge,
+ ),
+ (Closure,
+ BUG(sp, "Hit closure");
+ ),
+ (Primitive,
+ if( ae != be )
+ return false;
+ ),
+ (Path,
+ if( ae.path.m_data.tag() != be.path.m_data.tag() )
+ return false;
+ TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe),
+ (Generic,
+ if( ape.m_path != bpe.m_path )
+ return false;
+ return H::types_overlap(ape.m_params, bpe.m_params);
+ ),
+ (UfcsUnknown,
+ ),
+ (UfcsKnown,
+ ),
+ (UfcsInherent,
+ )
+ )
+ TODO(sp, "Path - " << ae.path << " and " << be.path);
+ ),
+ (TraitObject,
+ if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path )
+ return false;
+ if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) )
+ return false;
+ // Marker traits only overlap if the lists are the same (with overlap)
+ if( ae.m_markers.size() != be.m_markers.size() )
+ return false;
+ for(size_t i = 0; i < ae.m_markers.size(); i++)
+ {
+ if( ae.m_markers[i].m_path != be.m_markers[i].m_path )
+ return false;
+ if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) )
+ return false;
+ }
+ return true;
+ ),
+ (ErasedType,
+ TODO(sp, "ErasedType - " << a);
+ ),
+ (Function,
+ if( ae.is_unsafe != be.is_unsafe )
+ return false;
+ if( ae.m_abi != be.m_abi )
+ return false;
+ if( ae.m_arg_types.size() != be.m_arg_types.size() )
+ return false;
+ for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++)
+ {
+ if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) )
+ return false;
+ }
+ ),
+ (Tuple,
+ if( ae.size() != be.size() )
+ return false;
+ for(unsigned int i = 0; i < ae.size(); i ++)
+ {
+ if( ! H::types_overlap(ae[i], be[i]) )
+ return false;
+ }
+ ),
+ (Slice,
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Array,
+ if( ae.size_val != be.size_val )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Pointer,
+ if( ae.type != be.type )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Borrow,
+ if( ae.type != be.type )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ )
+ )
+ return true;
+ }
+ };
+
+ // Quick Check: If the types are equal, they do overlap
+ if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args)
+ {
+ return true;
+ }
+
+ // 1. Are the impl types of the same form (or is one generic)
+ if( ! H::types_overlap(this->m_type, other.m_type) )
+ return false;
+ if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) )
+ return false;
+
+ DEBUG("TODO: Handle potential overlap (when not exactly equal)");
+ //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args;
+ Span sp;
+
+ // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false`
+ try
+ {
+ type_ord_specific(sp, this->m_type, other.m_type);
+ typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
+ }
+ catch(const TypeOrdSpecific_MixedOrdering& /*e*/)
+ {
+ return false;
+ }
+
+ // TODO: Detect `impl<T> Foo<T> for Bar<T>` vs `impl<T> Foo<&T> for Bar<T>`
+ // > Create values for impl params from the type, then check if the trait params are compatible
+ // > Requires two lists, and telling which one to use by the end
+ auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
+ bool is_reversed = false;
+ ::std::vector<const ::HIR::TypeRef*> impl_tys;
+ auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
+ assert(idx < impl_tys.size());
+ if( impl_tys.at(idx) )
+ {
+ DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
+ return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
+ }
+ else
+ {
+ impl_tys.at(idx) = &x;
+ return ::HIR::Compare::Equal;
+ }
+ };
+ impl_tys.resize( this->m_params.m_types.size() );
+ if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch, try other ordering");
+ is_reversed = true;
+ impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
+ if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch in both orderings");
+ return false;
+ }
+ if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Params mismatch");
+ return false;
+ }
+ // Matched with second ording
+ }
+ else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Param mismatch, try other ordering");
+ is_reversed = true;
+ impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
+ if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch in alt ordering");
+ return false;
+ }
+ if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Params mismatch in alt ordering");
+ return false;
+ }
+ // Matched with second ordering
+ }
+ else
+ {
+ // Matched with first ordering
+ }
+
+ struct H2 {
+ static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TypeRef& tmp)
+ {
+ if( ! monomorphise_type_needed(in_ty) ) {
+ return in_ty;
+ }
+ else if( const auto* tep = in_ty.m_data.opt_Generic() ) {
+ ASSERT_BUG(sp, tep->binding < args.size(), "");
+ ASSERT_BUG(sp, args[tep->binding], "");
+ return *args[tep->binding];
+ }
+ else {
+ auto monomorph_cb = [&](const auto& t)->const auto& {
+ const auto& te = t.m_data.as_Generic();
+ assert(te.binding < args.size());
+ ASSERT_BUG(sp, te.binding < args.size(), "");
+ ASSERT_BUG(sp, args[te.binding], "");
+ return *args[te.binding];
+ };
+ tmp = monomorphise_type_with(sp, in_ty, monomorph_cb);
+ // TODO: EAT?
+ return tmp;
+ }
+ }
+ static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TraitPath& tmp)
+ {
+ if( ! monomorphise_traitpath_needed(in) ) {
+ return in;
+ }
+ else {
+ auto monomorph_cb = [&](const auto& t)->const auto& {
+ const auto& te = t.m_data.as_Generic();
+ assert(te.binding < args.size());
+ ASSERT_BUG(sp, te.binding < args.size(), "");
+ ASSERT_BUG(sp, args[te.binding], "");
+ return *args[te.binding];
+ };
+ tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true);
+ // TODO: EAT?
+ return tmp;
+ }
+ }
+ static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector<const ::HIR::TypeRef*>& args, const ::HIR::TraitImpl& g_src)
+ {
+ TRACE_FUNCTION;
+ static Span sp;
+ for(const auto& tb : id.m_params.m_bounds)
+ {
+ DEBUG(tb);
+ if(tb.is_TraitBound())
+ {
+ ::HIR::TypeRef tmp_ty;
+ ::HIR::TraitPath tmp_tp;
+ const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty);
+ const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);;
+
+ // Determine if `ty` would be bounded (it's an ATY or generic)
+ if( ty.m_data.is_Generic() ) {
+ bool found = false;
+ for(const auto& bound : g_src.m_params.m_bounds)
+ {
+ if(const auto* be = bound.opt_TraitBound())
+ {
+ if( be->type != ty ) continue;
+ if( be->trait != trait ) continue;
+ found = true;
+ }
+ }
+ if( !found )
+ {
+ DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds());
+ return false;
+ }
+ }
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) {
+ TODO(sp, "Check bound " << ty << " : " << trait << " in source bounds or trait bounds");
+ }
+ else {
+ // Search the crate for an impl
+ bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool {
+ DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds());
+
+ ::std::vector<const ::HIR::TypeRef*> impl_tys { ti.m_params.m_types.size() };
+ auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
+ auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
+ assert(idx < impl_tys.size());
+ if( impl_tys.at(idx) )
+ {
+ DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
+ return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
+ }
+ else
+ {
+ impl_tys.at(idx) = &x;
+ return ::HIR::Compare::Equal;
+ }
+ };
+ // 1. Triple-check the type matches (and get generics)
+ if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) )
+ return false;
+ // 2. Check trait params
+ assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size());
+ for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++)
+ {
+ if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) )
+ return false;
+ }
+ // 3. Check bounds on the impl
+ if( !H2::check_bounds(crate, ti, impl_tys, g_src) )
+ return false;
+ // 4. Check ATY bounds on the trait path
+ for(const auto& atyb : trait.m_type_bounds)
+ {
+ if( ti.m_types.count(atyb.first) == 0 ) {
+ DEBUG("Associated type '" << atyb.first << "' not in trait impl, assuming good");
+ }
+ else {
+ const auto& aty = ti.m_types.at(atyb.first);
+ if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) )
+ return false;
+ }
+ }
+ // All those pass? It's good.
+ return true;
+ });
+ if( !rv )
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // TODO: Other bound types?
+ }
+ }
+ // No bounds failed, it's good
+ return true;
+ }
+ };
+
+ // The two impls could overlap, pending on trait bounds
+ if(is_reversed)
+ {
+ DEBUG("(reversed) impl params " << FMT_CB(os,
+ for(auto* p : impl_tys)
+ {
+ if(p)
+ os << *p;
+ else
+ os << "?";
+ os << ",";
+ }
+ ));
+ // Check bounds on `other` using these params
+ // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result?
+ return H2::check_bounds(crate, other, impl_tys, *this);
+ }
+ else
+ {
+ DEBUG("impl params " << FMT_CB(os,
+ for(auto* p : impl_tys)
+ {
+ if(p)
+ os << *p;
+ else
+ os << "?";
+ os << ",";
+ }
+ ));
+ // Check bounds on `*this`
+ return H2::check_bounds(crate, *this, impl_tys, other);
+ }
+}
+
+namespace
+{
+ template<typename ImplType>
+ bool find_impls_list(const typename ::HIR::Crate::ImplGroup<ImplType>::list_t& impl_list, const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ImplType&)> callback)
+ {
+ for(const auto& impl : impl_list)
+ {
+ if( impl->matches_type(type, ty_res) )
+ {
+ if( callback(*impl) )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+namespace
+{
+ bool find_trait_impls_int(
+ const ::HIR::Crate& crate, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type,
+ ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback
+ )
+ {
+ auto it = crate.m_trait_impls.find( trait );
+ if( it != crate.m_trait_impls.end() )
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = it->second.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list.
+ if( find_impls_list(it->second.generic, type, ty_res, callback) )
+ return true;
+ }
+
+ return false;
+ }
+}
+
+bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const
+{
+ if( find_trait_impls_int(*this, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ if( find_trait_impls_int(*ec.second.m_data, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+namespace
+{
+ bool find_auto_trait_impls_int(
+ const ::HIR::Crate& crate, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type,
+ ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback
+ )
+ {
+ auto it = crate.m_marker_impls.find( trait );
+ if( it != crate.m_marker_impls.end() )
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = it->second.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list.
+ if( find_impls_list(it->second.generic, type, ty_res, callback) )
+ return true;
+ }
+
+ return false;
+ }
+}
+bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const
+{
+ if( find_auto_trait_impls_int(*this, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ if( find_auto_trait_impls_int(*ec.second.m_data, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+namespace
+{
+ bool find_type_impls_int(const ::HIR::Crate& crate, const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback)
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = crate.m_type_impls.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list?
+ if( find_impls_list(crate.m_type_impls.generic, type, ty_res, callback) )
+ return true;
+
+ return false;
+ }
+}
+bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const
+{
+ // > Current crate
+ if( find_type_impls_int(*this, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ //DEBUG("- " << ec.first);
+ if( find_type_impls_int(*ec.second.m_data, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const
+{
+ if( !ep )
+ {
+ // No HIR, so has to just have MIR - from a extern crate most likely
+ assert(ep.m_mir);
+ return &*ep.m_mir;
+ }
+ else
+ {
+ if( !ep.m_mir )
+ {
+ TRACE_FUNCTION_F(ip);
+ ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip);
+
+ auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep);
+
+ // TODO: Ensure that all referenced items have constants evaluated
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::ConstEval )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::ConstEvalRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::ConstEvalRequest;
+ ConvertHIR_ConstantEvaluate_Expr(*this, ip, ep_mut);
+ ep.m_state->stage = ::HIR::ExprState::Stage::ConstEval;
+ }
+
+ // Ensure typechecked
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest;
+
+ // TODO: Set debug/timing stage
+ //Debug_SetStagePre("HIR Typecheck");
+ // - Can store that on the Expr, OR get it from the item path
+ typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) };
+ //ms.prepare_from_path( ip ); // <- Ideally would use this, but it's a lot of code for one usage
+ ms.m_impl_generics = ep.m_state->m_impl_generics;
+ ms.m_item_generics = ep.m_state->m_item_generics;
+ ms.m_traits = ep.m_state->m_traits;
+ ms.m_mod_paths.push_back(ep.m_state->m_mod_path);
+ Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut);
+ //Debug_SetStagePre("Expand HIR Annotate");
+ HIR_Expand_AnnotateUsage_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Closures");
+ HIR_Expand_Closures_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Calls");
+ HIR_Expand_UfcsEverything_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Reborrows");
+ HIR_Expand_Reborrows_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR ErasedType");
+ //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe?
+ //Typecheck_Expressions_Validate(*hir_crate);
+
+ ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
+ }
+ // Generate MIR
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest;
+ //Debug_SetStage("Lower MIR");
+ HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty);
+ ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
+ }
+ assert(ep.m_mir);
+ }
+ return &*ep.m_mir;
+ }
+}
diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp
index d19435eb..091a45c9 100644
--- a/src/hir/item_path.hpp
+++ b/src/hir/item_path.hpp
@@ -20,7 +20,9 @@ public:
const char* crate_name = nullptr;
const ::HIR::Path* wrapped = nullptr;
+ ItemPath(const char* crate): crate_name(crate) {}
ItemPath(const ::std::string& crate): crate_name(crate.c_str()) {}
+ ItemPath(const RcString& crate): crate_name(crate.c_str()) {}
ItemPath(const ItemPath& p, const char* n):
parent(&p),
name(n)
@@ -54,12 +56,12 @@ public:
}
else if( parent ) {
assert(name);
- return parent->get_simple_path() + name;
+ return parent->get_simple_path() + RcString::new_interned(name);
}
else {
assert(!name);
assert(crate_name);
- return ::HIR::SimplePath(crate_name);
+ return ::HIR::SimplePath(RcString::new_interned(crate_name));
}
}
::HIR::Path get_full_path() const {
@@ -76,20 +78,28 @@ public:
else if( parent->trait ) {
assert(parent->ty);
assert(parent->trait_params);
- return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), ::std::string(name) );
+ return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), RcString::new_interned(name) );
}
else {
assert(parent->ty);
- return ::HIR::Path( parent->ty->clone(), ::std::string(name) );
+ return ::HIR::Path( parent->ty->clone(), RcString::new_interned(name) );
}
}
const char* get_name() const {
return name ? name : "";
}
+ const ItemPath& get_top_ip() const {
+ if( this->parent )
+ return this->parent->get_top_ip();
+ return *this;
+ }
ItemPath operator+(const ::std::string& name) const {
return ItemPath(*this, name.c_str());
}
+ ItemPath operator+(const RcString& name) const {
+ return ItemPath(*this, name.c_str());
+ }
bool operator==(const ::HIR::SimplePath& sp) const {
if( sp.m_crate_name != "" ) return false;
@@ -133,7 +143,7 @@ public:
os << "<* as " << *x.trait << ">";
}
else if( x.crate_name ) {
- os << "\"" << x.crate_name << "\"";
+ os << "::\"" << x.crate_name << "\"";
}
return os;
}
diff --git a/src/hir/main_bindings.hpp b/src/hir/main_bindings.hpp
index 622d8e2e..89896df0 100644
--- a/src/hir/main_bindings.hpp
+++ b/src/hir/main_bindings.hpp
@@ -18,4 +18,4 @@ namespace AST {
extern void HIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate);
extern ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate);
extern void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate);
-extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name);
+extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename);
diff --git a/src/hir/path.cpp b/src/hir/path.cpp
index e6dab41f..a867c245 100644
--- a/src/hir/path.cpp
+++ b/src/hir/path.cpp
@@ -8,7 +8,7 @@
#include <hir/path.hpp>
#include <hir/type.hpp>
-::HIR::SimplePath HIR::SimplePath::operator+(const ::std::string& s) const
+::HIR::SimplePath HIR::SimplePath::operator+(const RcString& s) const
{
::HIR::SimplePath ret(m_crate_name);
ret.m_components = m_components;
@@ -193,11 +193,11 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const
m_data( ::HIR::Path::Data::make_Generic(::HIR::GenericPath(mv$(sp))) )
{
}
-::HIR::Path::Path(TypeRef ty, ::std::string item, PathParams item_params):
+::HIR::Path::Path(TypeRef ty, RcString item, PathParams item_params):
m_data(Data::make_UfcsInherent({ box$(ty), mv$(item), mv$(item_params) }))
{
}
-::HIR::Path::Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params):
+::HIR::Path::Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params):
m_data( Data::make_UfcsKnown({ box$(mv$(ty)), mv$(trait), mv$(item), mv$(item_params) }) )
{
}
diff --git a/src/hir/path.hpp b/src/hir/path.hpp
index f2bec6ee..86fe725e 100644
--- a/src/hir/path.hpp
+++ b/src/hir/path.hpp
@@ -25,7 +25,7 @@ enum Compare {
};
typedef ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> t_cb_resolve_type;
-typedef ::std::function< ::HIR::Compare(unsigned int, const ::std::string&, const ::HIR::TypeRef&) > t_cb_match_generics;
+typedef ::std::function< ::HIR::Compare(unsigned int, const RcString&, const ::HIR::TypeRef&) > t_cb_match_generics;
static inline ::std::ostream& operator<<(::std::ostream& os, const Compare& x) {
switch(x)
@@ -54,18 +54,18 @@ static inline Compare& operator &=(Compare& x, const Compare& y) {
/// Simple path - Absolute with no generic parameters
struct SimplePath
{
- ::std::string m_crate_name;
- ::std::vector< ::std::string> m_components;
+ RcString m_crate_name;
+ ::std::vector< RcString> m_components;
SimplePath():
m_crate_name("")
{
}
- SimplePath(::std::string crate):
+ SimplePath(RcString crate):
m_crate_name( mv$(crate) )
{
}
- SimplePath(::std::string crate, ::std::vector< ::std::string> components):
+ SimplePath(RcString crate, ::std::vector< RcString> components):
m_crate_name( mv$(crate) ),
m_components( mv$(components) )
{
@@ -73,7 +73,7 @@ struct SimplePath
SimplePath clone() const;
- SimplePath operator+(const ::std::string& s) const;
+ SimplePath operator+(const RcString& s) const;
bool operator==(const SimplePath& x) const {
return m_crate_name == x.m_crate_name && m_components == x.m_components;
}
@@ -158,9 +158,9 @@ class TraitPath
{
public:
GenericPath m_path;
- ::std::vector< ::std::string> m_hrls;
+ ::std::vector< RcString> m_hrls;
// TODO: Each bound should list its origin trait
- ::std::map< ::std::string, ::HIR::TypeRef> m_type_bounds;
+ ::std::map< RcString, ::HIR::TypeRef> m_type_bounds;
const ::HIR::Trait* m_trait_ptr;
@@ -190,20 +190,20 @@ public:
(Generic, GenericPath),
(UfcsInherent, struct {
::std::unique_ptr<TypeRef> type;
- ::std::string item;
+ RcString item;
PathParams params;
PathParams impl_params;
}),
(UfcsKnown, struct {
::std::unique_ptr<TypeRef> type;
GenericPath trait;
- ::std::string item;
+ RcString item;
PathParams params;
}),
(UfcsUnknown, struct {
::std::unique_ptr<TypeRef> type;
//GenericPath ??;
- ::std::string item;
+ RcString item;
PathParams params;
})
);
@@ -216,8 +216,8 @@ public:
Path(GenericPath _);
Path(SimplePath _);
- Path(TypeRef ty, ::std::string item, PathParams item_params=PathParams());
- Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params=PathParams());
+ Path(TypeRef ty, RcString item, PathParams item_params=PathParams());
+ Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params=PathParams());
Path clone() const;
Compare compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const;
diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp
index da6446d7..063ed1b3 100644
--- a/src/hir/pattern.cpp
+++ b/src/hir/pattern.cpp
@@ -46,6 +46,9 @@ namespace HIR {
if( x.m_binding.is_valid() ) {
os << x.m_binding;
}
+ if( x.m_implicit_deref_count > 0 ) {
+ os << "&*" << x.m_implicit_deref_count;
+ }
TU_MATCH(Pattern::Data, (x.m_data), (e),
(Any,
os << "_";
@@ -151,8 +154,9 @@ namespace {
rv.push_back( pat.clone() );
return rv;
}
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > clone_pat_fields(const ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> >& pats) {
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > rv;
+ typedef ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > pat_fields_t;
+ pat_fields_t clone_pat_fields(const pat_fields_t& pats) {
+ pat_fields_t rv;
rv.reserve( pats.size() );
for(const auto& field : pats)
rv.push_back( ::std::make_pair(field.first, field.second.clone()) );
@@ -181,102 +185,108 @@ namespace {
}
} // namespace
-::HIR::Pattern HIR::Pattern::clone() const
+namespace { ::HIR::Pattern::Data clone_pattern_data(const ::HIR::Pattern::Data& m_data)
{
TU_MATCH(::HIR::Pattern::Data, (m_data), (e),
(Any,
- return Pattern(m_binding, Data::make_Any({}));
+ return ::HIR::Pattern::Data::make_Any({});
),
(Box,
- return Pattern(m_binding, Data::make_Box({
+ return ::HIR::Pattern::Data::make_Box({
box$( e.sub->clone() )
- }));
+ });
),
(Ref,
- return Pattern(m_binding, Data::make_Ref({
+ return ::HIR::Pattern::Data::make_Ref({
e.type, box$(e.sub->clone())
- }));
+ });
),
(Tuple,
- return Pattern(m_binding, Data::make_Tuple({
+ return ::HIR::Pattern::Data::make_Tuple({
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(SplitTuple,
- return Pattern(m_binding, Data::make_SplitTuple({
+ return ::HIR::Pattern::Data::make_SplitTuple({
clone_pat_vec(e.leading),
clone_pat_vec(e.trailing),
e.total_size
- }));
+ });
),
(StructValue,
- return Pattern(m_binding, Data::make_StructValue({
+ return ::HIR::Pattern::Data::make_StructValue({
e.path.clone(), e.binding
- }));
+ });
),
(StructTuple,
- return Pattern(m_binding, Data::make_StructTuple({
+ return ::HIR::Pattern::Data::make_StructTuple({
e.path.clone(),
e.binding,
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(Struct,
- return Pattern(m_binding, Data::make_Struct({
+ return ::HIR::Pattern::Data::make_Struct({
e.path.clone(),
e.binding,
clone_pat_fields(e.sub_patterns),
e.is_exhaustive
- }));
+ });
),
(Value,
- return Pattern(m_binding, Data::make_Value({
+ return ::HIR::Pattern::Data::make_Value({
clone_patval(e.val)
- }));
+ });
),
(Range,
- return Pattern(m_binding, Data::make_Range({
+ return ::HIR::Pattern::Data::make_Range({
clone_patval(e.start),
clone_patval(e.end)
- }));
+ });
),
(EnumValue,
- return Pattern(m_binding, Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx }));
+ return ::HIR::Pattern::Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx });
),
(EnumTuple,
- return Pattern(m_binding, Data::make_EnumTuple({
+ return ::HIR::Pattern::Data::make_EnumTuple({
e.path.clone(),
e.binding_ptr,
e.binding_idx,
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(EnumStruct,
- return Pattern(m_binding, Data::make_EnumStruct({
+ return ::HIR::Pattern::Data::make_EnumStruct({
e.path.clone(),
e.binding_ptr,
e.binding_idx,
clone_pat_fields(e.sub_patterns),
e.is_exhaustive
- }));
+ });
),
(Slice,
- return Pattern(m_binding, Data::make_Slice({
+ return ::HIR::Pattern::Data::make_Slice({
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(SplitSlice,
- return Pattern(m_binding, Data::make_SplitSlice({
+ return ::HIR::Pattern::Data::make_SplitSlice({
clone_pat_vec(e.leading),
e.extra_bind,
clone_pat_vec(e.trailing)
- }));
+ });
)
)
throw "";
+} }
+::HIR::Pattern HIR::Pattern::clone() const
+{
+ auto rv = Pattern(m_binding, clone_pattern_data(m_data));
+ rv.m_implicit_deref_count = m_implicit_deref_count;
+ return rv;
}
diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp
index df14de79..136bd587 100644
--- a/src/hir/pattern.hpp
+++ b/src/hir/pattern.hpp
@@ -29,22 +29,26 @@ struct PatternBinding
bool m_mutable;
Type m_type;
- ::std::string m_name;
+ RcString m_name;
unsigned int m_slot;
+ unsigned m_implicit_deref_count = 0;
+
bool is_valid() const { return m_name != ""; }
PatternBinding():
m_mutable(false),
m_type(Type::Move),
m_name(""),
- m_slot(0)
+ m_slot(0),
+ m_implicit_deref_count(0)
{}
- PatternBinding(bool mut, Type type, ::std::string name, unsigned int slot):
+ PatternBinding(bool mut, Type type, RcString name, unsigned int slot):
m_mutable(mut),
m_type(type),
m_name( mv$(name) ),
- m_slot( slot )
+ m_slot( slot ),
+ m_implicit_deref_count(0)
{}
};
@@ -100,8 +104,12 @@ struct Pattern
(Struct, struct {
GenericPath path;
const Struct* binding;
- ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns;
+ ::std::vector< ::std::pair<RcString, Pattern> > sub_patterns;
bool is_exhaustive;
+
+ bool is_wildcard() const {
+ return sub_patterns.empty() && !is_exhaustive;
+ }
} ),
// Refutable
(Value, struct { Value val; } ),
@@ -121,7 +129,7 @@ struct Pattern
GenericPath path;
const Enum* binding_ptr;
unsigned binding_idx;
- ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns;
+ ::std::vector< ::std::pair<RcString, Pattern> > sub_patterns;
bool is_exhaustive;
} ),
(Slice, struct {
@@ -136,6 +144,7 @@ struct Pattern
PatternBinding m_binding;
Data m_data;
+ unsigned m_implicit_deref_count = 0;
Pattern() {}
Pattern(PatternBinding pb, Data d):
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 50da4453..9acb6193 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -21,6 +21,15 @@
{}
template<typename V>
+ void serialise_strmap(const ::std::map<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::map< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -30,6 +39,26 @@
}
}
template<typename V>
+ void serialise_pathmap(const ::std::map< ::HIR::SimplePath,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ serialise(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
+ void serialise_strmap(const ::std::unordered_map<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::unordered_map< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -40,6 +69,16 @@
}
}
template<typename V>
+ void serialise_strmap(const ::std::unordered_multimap<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::unordered_multimap< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -58,9 +97,14 @@
serialise(i);
}
template<typename T>
+ void serialise(const ::std::vector<T>& vec)
+ {
+ serialise_vec(vec);
+ }
+ template<typename T>
void serialise(const ::HIR::VisEnt<T>& e)
{
- m_out.write_bool(e.is_public);
+ m_out.write_bool(e.publicity.is_global()); // At this stage, we only care if the item is visible outside the crate or not
serialise(e.ent);
}
template<typename T>
@@ -73,6 +117,11 @@
serialise(e.second);
}
template<typename T>
+ void serialise(const ::std::pair< RcString, T>& e) {
+ m_out.write_string(e.first);
+ serialise(e.second);
+ }
+ template<typename T>
void serialise(const ::std::pair<unsigned int, T>& e) {
m_out.write_count(e.first);
serialise(e.second);
@@ -86,6 +135,10 @@
void serialise(uint64_t v) { m_out.write_u64c(v); };
void serialise(int64_t v) { m_out.write_i64c(v); };
+ void serialise(const ::HIR::LifetimeDef& ld)
+ {
+ m_out.write_string(ld.m_name);
+ }
void serialise(const ::HIR::LifetimeRef& lr)
{
m_out.write_count(lr.binding);
@@ -255,28 +308,29 @@
serialise(pm.path);
serialise_vec(pm.attributes);
}
+ template<typename T>
+ void serialise(const ::HIR::Crate::ImplGroup<T>& ig)
+ {
+ serialise_pathmap(ig.named);
+ serialise_vec(ig.non_named);
+ serialise_vec(ig.generic);
+ }
+ void serialise(const ::HIR::Crate::MacroImport& e)
+ {
+ serialise(e.path);
+ }
void serialise_crate(const ::HIR::Crate& crate)
{
m_out.write_string(crate.m_crate_name);
serialise_module(crate.m_root_module);
- m_out.write_count(crate.m_type_impls.size());
- for(const auto& impl : crate.m_type_impls) {
- serialise_typeimpl(impl);
- }
- m_out.write_count(crate.m_trait_impls.size());
- for(const auto& tr_impl : crate.m_trait_impls) {
- serialise_simplepath(tr_impl.first);
- serialise_traitimpl(tr_impl.second);
- }
- m_out.write_count(crate.m_marker_impls.size());
- for(const auto& tr_impl : crate.m_marker_impls) {
- serialise_simplepath(tr_impl.first);
- serialise_markerimpl(tr_impl.second);
- }
+ serialise(crate.m_type_impls);
+ serialise_pathmap(crate.m_trait_impls);
+ serialise_pathmap(crate.m_marker_impls);
serialise_strmap(crate.m_exported_macros);
+ serialise_strmap(crate.m_proc_macro_reexports);
{
decltype(crate.m_lang_items) lang_items_filtered;
for(const auto& ent : crate.m_lang_items)
@@ -293,7 +347,8 @@
for(const auto& ext : crate.m_ext_crates)
{
m_out.write_string(ext.first);
- m_out.write_string(ext.second.m_basename);
+ //m_out.write_string(ext.second.m_basename);
+ m_out.write_string(ext.second.m_path);
}
serialise_vec(crate.m_ext_libs);
serialise_vec(crate.m_link_paths);
@@ -322,19 +377,23 @@
m_out.write_count(impl.m_methods.size());
for(const auto& v : impl.m_methods) {
m_out.write_string(v.first);
- m_out.write_bool(v.second.is_pub);
+ m_out.write_bool(v.second.publicity.is_global());
m_out.write_bool(v.second.is_specialisable);
serialise(v.second.data);
}
m_out.write_count(impl.m_constants.size());
for(const auto& v : impl.m_constants) {
m_out.write_string(v.first);
- m_out.write_bool(v.second.is_pub);
+ m_out.write_bool(v.second.publicity.is_global());
m_out.write_bool(v.second.is_specialisable);
serialise(v.second.data);
}
// m_src_module doesn't matter after typeck
}
+ void serialise(const ::HIR::TypeImpl& impl)
+ {
+ serialise_typeimpl(impl);
+ }
void serialise_traitimpl(const ::HIR::TraitImpl& impl)
{
TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " ?" << impl.m_trait_args << " for " << impl.m_type);
@@ -372,6 +431,10 @@
}
// m_src_module doesn't matter after typeck
}
+ void serialise(const ::HIR::TraitImpl& impl)
+ {
+ serialise_traitimpl(impl);
+ }
void serialise_markerimpl(const ::HIR::MarkerImpl& impl)
{
serialise_generics(impl.m_params);
@@ -379,6 +442,10 @@
m_out.write_bool(impl.is_positive);
serialise_type(impl.m_type);
}
+ void serialise(const ::HIR::MarkerImpl& impl)
+ {
+ serialise_markerimpl(impl);
+ }
void serialise(const ::HIR::TypeRef& ty) {
serialise_type(ty);
@@ -392,6 +459,9 @@
void serialise(const ::std::string& v) {
m_out.write_string(v);
}
+ void serialise(const RcString& v) {
+ m_out.write_string(v);
+ }
void serialise(const ::MacroRulesPtr& mac)
{
@@ -400,6 +470,7 @@
void serialise(const ::MacroRules& mac)
{
//m_exported: IGNORE, should be set
+ assert(mac.m_rules.size() > 0);
serialise_vec(mac.m_rules);
m_out.write_string(mac.m_source_crate);
}
@@ -415,6 +486,34 @@
serialise_vec(pe.subpats);
}
}
+ void serialise(const ::SimplePatIfCheck& e) {
+ m_out.write_tag( static_cast<int>(e.ty) );
+ serialise(e.tok);
+ }
+ void serialise(const ::SimplePatEnt& pe) {
+ m_out.write_tag( pe.tag() );
+ TU_MATCH_HDRA( (pe), { )
+ TU_ARMA(End, _e) {}
+ TU_ARMA(LoopStart, _e) {}
+ TU_ARMA(LoopNext, _e) {}
+ TU_ARMA(LoopEnd, _e) {}
+ TU_ARMA(Jump, e) {
+ m_out.write_count(e.jump_target);
+ }
+ TU_ARMA(ExpectTok, e) {
+ serialise(e);
+ }
+ TU_ARMA(ExpectPat, e) {
+ m_out.write_tag( static_cast<int>(e.type) );
+ m_out.write_count(e.idx);
+ }
+ TU_ARMA(If, e) {
+ m_out.write_bool(e.is_equal);
+ m_out.write_count(e.jump_target);
+ serialise_vec(e.ents);
+ }
+ }
+ }
void serialise(const ::MacroRulesArm& arm) {
serialise_vec(arm.m_param_names);
serialise_vec(arm.m_pattern);
@@ -459,6 +558,9 @@
TU_ARM(td, String, e) {
m_out.write_string(e);
} break;
+ TU_ARM(td, IString, e) {
+ m_out.write_string(e);
+ } break;
TU_ARM(td, Integer, e) {
m_out.write_tag(e.m_datatype);
m_out.write_u64c(e.m_intval);
@@ -479,6 +581,8 @@
(Invalid,
//BUG(Span(), "Literal::Invalid encountered in HIR");
),
+ (Defer,
+ ),
(List,
serialise_vec(e);
),
@@ -647,35 +751,18 @@
void serialise(const ::MIR::LValue& lv)
{
TRACE_FUNCTION_F("LValue = "<<lv);
- m_out.write_tag( static_cast<int>(lv.tag()) );
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- m_out.write_count(e.idx);
- ),
- (Local,
- m_out.write_count(e);
- ),
- (Static,
- serialise_path(e);
- ),
- (Field,
- serialise(e.val);
- m_out.write_count(e.field_index);
- ),
- (Deref,
- serialise(e.val);
- ),
- (Index,
- serialise(e.val);
- serialise(e.idx);
- ),
- (Downcast,
- serialise(e.val);
- m_out.write_count(e.variant_index);
- )
- )
+ if( lv.m_root.is_Static() ) {
+ m_out.write_count(3);
+ serialise_path(lv.m_root.as_Static());
+ }
+ else {
+ m_out.write_count( lv.m_root.get_inner() );
+ }
+ serialise_vec(lv.m_wrappers);
+ }
+ void serialise(const ::MIR::LValue::Wrapper& w)
+ {
+ m_out.write_count(w.get_inner());
}
void serialise(const ::MIR::RValue& val)
{
@@ -764,10 +851,10 @@
m_out.write_string(e);
),
(Const,
- serialise_path(e.p);
+ serialise_path(*e.p);
),
(ItemAddr,
- serialise_path(e);
+ serialise_path(*e);
)
)
}
@@ -804,6 +891,10 @@
(Union,
m_out.write_tag(6);
serialise(e);
+ ),
+ (ExternType,
+ m_out.write_tag(7);
+ serialise(e);
)
)
}
@@ -975,6 +1066,7 @@
)
)
+ m_out.write_u64c(item.m_forced_alignment);
serialise(item.m_markings);
serialise(item.m_struct_markings);
}
@@ -989,6 +1081,11 @@
serialise(item.m_markings);
}
+ void serialise(const ::HIR::ExternType& item)
+ {
+ TRACE_FUNCTION_F("ExternType");
+ serialise(item.m_markings);
+ }
void serialise(const ::HIR::Trait& item)
{
TRACE_FUNCTION_F("_trait:");
@@ -1000,6 +1097,7 @@
serialise_strmap( item.m_value_indexes );
serialise_strmap( item.m_type_indexes );
serialise_vec( item.m_all_parent_traits );
+ serialise( item.m_vtable_path );
}
void serialise(const ::HIR::TraitValueItem& tvi)
{
@@ -1022,7 +1120,7 @@
void serialise(const ::HIR::AssociatedType& at)
{
m_out.write_bool(at.is_sized);
- //m_out.write_string(at.m_lifetime_bound); // TODO: better type for lifetime
+ serialise(at.m_lifetime_bound);
serialise_vec(at.m_trait_bounds);
serialise_type(at.m_default);
}
@@ -1031,8 +1129,10 @@
void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate)
{
- ::HIR::serialise::Writer out { filename };
+ ::HIR::serialise::Writer out;
HirSerialiser s { out };
s.serialise_crate(crate);
+ out.open(filename);
+ s.serialise_crate(crate);
}
diff --git a/src/hir/serialise_lowlevel.cpp b/src/hir/serialise_lowlevel.cpp
index cf8f5506..5c4b0df2 100644
--- a/src/hir/serialise_lowlevel.cpp
+++ b/src/hir/serialise_lowlevel.cpp
@@ -11,6 +11,7 @@
#include <fstream>
#include <string.h> // memcpy
#include <common.hpp>
+#include <algorithm>
namespace HIR {
namespace serialise {
@@ -29,17 +30,58 @@ public:
void write(const void* buf, size_t len);
};
-Writer::Writer(const ::std::string& filename):
- m_inner( new WriterInner(filename) )
+Writer::Writer():
+ m_inner(nullptr)
{
}
Writer::~Writer()
{
delete m_inner, m_inner = nullptr;
}
+void Writer::open(const ::std::string& filename)
+{
+ // 1. Sort strings by frequency
+ ::std::vector<::std::pair<RcString, unsigned>> sorted;
+ sorted.reserve(m_istring_cache.size());
+ for(const auto& e : m_istring_cache)
+ sorted.push_back( e );
+ // 2. Write out string table
+ ::std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b){ return a.second > b.second; });
+
+ m_inner = new WriterInner(filename);
+ // 3. Reset m_istring_cache to use the same value
+ this->write_count(sorted.size());
+ for(size_t i = 0; i < sorted.size(); i ++)
+ {
+ const auto& s = sorted[i].first;
+ this->write_string(s.size(), s.c_str());
+ DEBUG(i << " = " << m_istring_cache[s] << " '" << s << "'");
+ m_istring_cache[s] = i;
+ }
+ for(const auto& e : m_istring_cache)
+ {
+ assert(e.second < sorted.size());
+ }
+}
void Writer::write(const void* buf, size_t len)
{
- m_inner->write(buf, len);
+ if( m_inner ) {
+ m_inner->write(buf, len);
+ }
+ else {
+ // No-op, pre caching
+ }
+}
+void Writer::write_string(const RcString& v)
+{
+ if( m_inner ) {
+ // Emit ID from the cache
+ this->write_count( m_istring_cache.at(v) );
+ }
+ else {
+ // Find/add in cache
+ m_istring_cache.insert(::std::make_pair(v, 0)).first->second += 1;
+ }
}
@@ -186,8 +228,17 @@ void ReadBuffer::populate(ReaderInner& is)
Reader::Reader(const ::std::string& filename):
m_inner( new ReaderInner(filename) ),
- m_buffer(1024)
+ m_buffer(1024),
+ m_pos(0)
{
+ size_t n_strings = read_count();
+ m_strings.reserve(n_strings);
+ DEBUG("n_strings = " << n_strings);
+ for(size_t i = 0; i < n_strings; i ++)
+ {
+ auto s = read_string();
+ m_strings.push_back( RcString::new_interned(s) );
+ }
}
Reader::~Reader()
{
@@ -198,6 +249,7 @@ void Reader::read(void* buf, size_t len)
{
auto used = m_buffer.read(buf, len);
if( used == len ) {
+ m_pos += len;
return ;
}
buf = reinterpret_cast<uint8_t*>(buf) + used;
@@ -214,6 +266,8 @@ void Reader::read(void* buf, size_t len)
if( used != len )
throw ::std::runtime_error( FMT("Reader::read - Requested " << len << " bytes from buffer, got " << used) );
}
+
+ m_pos += len;
}
diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp
index 6be8ff8c..b3633d54 100644
--- a/src/hir/serialise_lowlevel.hpp
+++ b/src/hir/serialise_lowlevel.hpp
@@ -9,8 +9,10 @@
#include <vector>
#include <string>
+#include <map>
#include <stddef.h>
#include <assert.h>
+#include <rc_string.hpp>
namespace HIR {
namespace serialise {
@@ -21,12 +23,14 @@ class ReaderInner;
class Writer
{
WriterInner* m_inner;
+ ::std::map<RcString, unsigned> m_istring_cache;
public:
- Writer(const ::std::string& path);
+ Writer();
Writer(const Writer&) = delete;
Writer(Writer&&) = delete;
~Writer();
+ void open(const ::std::string& filename);
void write(const void* data, size_t count);
void write_u8(uint8_t v) {
@@ -114,16 +118,20 @@ public:
write_u16( static_cast<uint16_t>(c) );
}
}
- void write_string(const ::std::string& v) {
- if(v.size() < 128) {
- write_u8( static_cast<uint8_t>(v.size()) );
+ void write_string(const RcString& v);
+ void write_string(size_t len, const char* s) {
+ if(len < 128) {
+ write_u8( static_cast<uint8_t>(len) );
}
else {
- assert(v.size() < (1u<<(16+7)));
- write_u8( static_cast<uint8_t>(128 + (v.size() >> 16)) );
- write_u16( static_cast<uint16_t>(v.size() & 0xFFFF) );
+ assert(len < (1u<<(16+7)));
+ write_u8( static_cast<uint8_t>(128 + (len >> 16)) );
+ write_u16( static_cast<uint16_t>(len & 0xFFFF) );
}
- this->write(v.data(), v.size());
+ this->write(s, len);
+ }
+ void write_string(const ::std::string& v) {
+ write_string(v.size(), v.c_str());
}
void write_bool(bool v) {
write_u8(v ? 0xFF : 0x00);
@@ -147,12 +155,15 @@ class Reader
{
ReaderInner* m_inner;
ReadBuffer m_buffer;
+ size_t m_pos;
+ ::std::vector<RcString> m_strings;
public:
Reader(const ::std::string& path);
Reader(const Writer&) = delete;
Reader(Writer&&) = delete;
~Reader();
+ size_t get_pos() const { return m_pos; }
void read(void* dst, size_t count);
uint8_t read_u8() {
@@ -249,6 +260,10 @@ public:
return ~0u;
}
}
+ RcString read_istring() {
+ size_t idx = read_count();
+ return m_strings.at(idx);
+ }
::std::string read_string() {
size_t len = read_u8();
if( len < 128 ) {
diff --git a/src/hir/type.cpp b/src/hir/type.cpp
index 6f826111..6e8eaaa9 100644
--- a/src/hir/type.cpp
+++ b/src/hir/type.cpp
@@ -58,8 +58,8 @@ namespace HIR {
void ::HIR::TypeRef::fmt(::std::ostream& os) const
{
- TU_MATCH(::HIR::TypeRef::Data, (m_data), (e),
- (Infer,
+ TU_MATCH_HDR( (m_data), { )
+ TU_ARM(m_data, Infer, e) {
os << "_";
if( e.index != ~0u || e.ty_class != ::HIR::InferClass::None ) {
os << "/*";
@@ -73,24 +73,25 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
}
os << "*/";
}
- ),
- (Diverge,
+ }
+ TU_ARM(m_data, Diverge, e) {
os << "!";
- ),
- (Primitive,
+ }
+ TU_ARM(m_data, Primitive, e) {
os << e;
- ),
- (Path,
+ }
+ TU_ARM(m_data, Path, e) {
os << e.path;
TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
(Unbound, os << "/*?*/";),
(Opaque, os << "/*O*/";),
+ (ExternType, os << "/*X*/";),
(Struct, os << "/*S*/";),
(Union, os << "/*U*/";),
(Enum, os << "/*E*/";)
)
- ),
- (Generic,
+ }
+ TU_ARM(m_data, Generic, e) {
os << e.name << "/*";
if( e.binding == 0xFFFF )
os << "";
@@ -103,8 +104,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
else
os << e.binding;
os << "*/";
- ),
- (TraitObject,
+ }
+ TU_ARM(m_data, TraitObject, e) {
os << "dyn (";
if( e.m_trait.m_path != ::HIR::GenericPath() )
{
@@ -115,8 +116,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
if( e.m_lifetime != LifetimeRef::new_static() )
os << "+" << e.m_lifetime;
os << ")";
- ),
- (ErasedType,
+ }
+ TU_ARM(m_data, ErasedType, e) {
os << "impl ";
for(const auto& tr : e.m_traits) {
if( &tr != &e.m_traits[0] )
@@ -126,25 +127,25 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
if( e.m_lifetime != LifetimeRef::new_static() )
os << "+ '" << e.m_lifetime;
os << "/*" << e.m_origin << "#" << e.m_index << "*/";
- ),
- (Array,
+ }
+ TU_ARM(m_data, Array, e) {
os << "[" << *e.inner << "; ";
if( e.size_val != ~0u )
os << e.size_val;
else
os << "/*sz*/";
os << "]";
- ),
- (Slice,
+ }
+ TU_ARM(m_data, Slice, e) {
os << "[" << *e.inner << "]";
- ),
- (Tuple,
+ }
+ TU_ARM(m_data, Tuple, e) {
os << "(";
for(const auto& t : e)
os << t << ", ";
os << ")";
- ),
- (Borrow,
+ }
+ TU_ARM(m_data, Borrow, e) {
switch(e.type)
{
case ::HIR::BorrowType::Shared: os << "&"; break;
@@ -152,8 +153,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
case ::HIR::BorrowType::Owned: os << "&move "; break;
}
os << *e.inner;
- ),
- (Pointer,
+ }
+ TU_ARM(m_data, Pointer, e) {
switch(e.type)
{
case ::HIR::BorrowType::Shared: os << "*const "; break;
@@ -161,8 +162,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
case ::HIR::BorrowType::Owned: os << "*move "; break;
}
os << *e.inner;
- ),
- (Function,
+ }
+ TU_ARM(m_data, Function, e) {
if( e.is_unsafe ) {
os << "unsafe ";
}
@@ -173,17 +174,15 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
for(const auto& t : e.m_arg_types)
os << t << ", ";
os << ") -> " << *e.m_rettype;
- ),
- (Closure,
+ }
+ TU_ARM(m_data, Closure, e) {
os << "closure["<<e.node<<"]";
- /*
os << "(";
for(const auto& t : e.m_arg_types)
os << t << ", ";
os << ") -> " << *e.m_rettype;
- */
- )
- )
+ }
+ }
}
bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const
@@ -782,6 +781,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this), (e),
(Unbound, return ::HIR::TypeRef::TypePathBinding::make_Unbound({}); ),
(Opaque , return ::HIR::TypeRef::TypePathBinding::make_Opaque({}); ),
+ (ExternType, return ::HIR::TypeRef::TypePathBinding(e); ),
(Struct, return ::HIR::TypeRef::TypePathBinding(e); ),
(Union , return ::HIR::TypeRef::TypePathBinding(e); ),
(Enum , return ::HIR::TypeRef::TypePathBinding(e); )
@@ -789,7 +789,34 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
assert(!"Fell off end of clone_binding");
throw "";
}
+bool HIR::TypeRef::TypePathBinding::operator==(const HIR::TypeRef::TypePathBinding& x) const
+{
+ if( this->tag() != x.tag() )
+ return false;
+ TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this, x), (te, xe),
+ (Unbound, return true;),
+ (Opaque, return true;),
+ (ExternType, return te == xe;),
+ (Struct, return te == xe;),
+ (Union , return te == xe;),
+ (Enum , return te == xe;)
+ )
+ throw "";
+}
+const ::HIR::TraitMarkings* HIR::TypeRef::TypePathBinding::get_trait_markings() const
+{
+ const ::HIR::TraitMarkings* markings_ptr = nullptr;
+ TU_MATCHA( (*this), (tpb),
+ (Unbound, ),
+ (Opaque, ),
+ (ExternType, markings_ptr = &tpb->m_markings; ),
+ (Struct, markings_ptr = &tpb->m_markings; ),
+ (Union, markings_ptr = &tpb->m_markings; ),
+ (Enum, markings_ptr = &tpb->m_markings; )
+ )
+ return markings_ptr;
+}
::HIR::TypeRef HIR::TypeRef::clone() const
{
@@ -889,7 +916,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
}
::HIR::Compare HIR::TypeRef::compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const
{
- TRACE_FUNCTION_F(*this << " ?= " << x);
+ //TRACE_FUNCTION_F(*this << " ?= " << x);
const auto& left = (m_data.is_Infer() || m_data.is_Generic() ? resolve_placeholder(*this) : *this);
//const auto& left = *this;
const auto& right = (x.m_data.is_Infer() ? resolve_placeholder(x) : (x.m_data.is_Generic() ? resolve_placeholder(x) : x));
@@ -899,6 +926,22 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
return Compare::Equal;
}
+ // Unbound paths and placeholder generics
+ if( left.m_data.tag() != right.m_data.tag() ) {
+ if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) {
+ return Compare::Fuzzy;
+ }
+ if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) {
+ return Compare::Fuzzy;
+ }
+ if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) {
+ return Compare::Fuzzy;
+ }
+ if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) {
+ return Compare::Fuzzy;
+ }
+ }
+
// If left is infer
TU_IFLET(::HIR::TypeRef::Data, left.m_data, Infer, e,
switch(e.ty_class)
@@ -1023,18 +1066,6 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
// - See `(Generic,` below
if( left.m_data.tag() != right.m_data.tag() ) {
- if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) {
- return Compare::Fuzzy;
- }
- if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) {
- return Compare::Fuzzy;
- }
- if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) {
- return Compare::Fuzzy;
- }
- if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) {
- return Compare::Fuzzy;
- }
return Compare::Unequal;
}
TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
diff --git a/src/hir/type.hpp b/src/hir/type.hpp
index 480b32c4..cbc2e94a 100644
--- a/src/hir/type.hpp
+++ b/src/hir/type.hpp
@@ -19,6 +19,8 @@
namespace HIR {
+class TraitMarkings;
+class ExternType;
class Struct;
class Union;
class Enum;
@@ -87,15 +89,28 @@ struct LifetimeRef
static const uint32_t UNKNOWN = 0;
static const uint32_t STATIC = 0xFFFF;
+ //RcString name;
// Values below 2^16 are parameters/static, values above are per-function region IDs allocated during region inferrence.
uint32_t binding = UNKNOWN;
+ LifetimeRef()
+ :binding(UNKNOWN)
+ {
+ }
+ LifetimeRef(uint32_t binding)
+ :binding(binding)
+ {
+ }
+
static LifetimeRef new_static() {
LifetimeRef rv;
rv.binding = STATIC;
return rv;
}
+ Ordering ord(const LifetimeRef& x) const {
+ return ::ord(binding, x.binding);
+ }
bool operator==(const LifetimeRef& x) const {
return binding == x.binding;
}
@@ -152,11 +167,17 @@ public:
TAGGED_UNION_EX(TypePathBinding, (), Unbound, (
(Unbound, struct {}), // Not yet bound, either during lowering OR during resolution (when associated and still being resolved)
(Opaque, struct {}), // Opaque, i.e. An associated type of a generic (or Self in a trait)
+ (ExternType, const ::HIR::ExternType*),
(Struct, const ::HIR::Struct*),
(Union, const ::HIR::Union*),
(Enum, const ::HIR::Enum*)
), (), (), (
TypePathBinding clone() const;
+
+ const TraitMarkings* get_trait_markings() const;
+
+ bool operator==(const TypePathBinding& x) const;
+ bool operator!=(const TypePathBinding& x) const { return !(*this == x); }
)
);
@@ -184,9 +205,16 @@ public:
(Path, struct {
::HIR::Path path;
TypePathBinding binding;
+
+ bool is_closure() const {
+ return path.m_data.is_Generic()
+ && path.m_data.as_Generic().m_path.m_components.back().size() > 8
+ && path.m_data.as_Generic().m_path.m_components.back().compare(0,8, "closure#") == 0
+ ;
+ }
}),
(Generic, struct {
- ::std::string name;
+ RcString name;
// 0xFFFF = Self, 0-255 = Type/Trait, 256-511 = Method, 512-767 = Placeholder
unsigned int binding;
@@ -208,7 +236,7 @@ public:
(Array, struct {
::std::unique_ptr<TypeRef> inner;
::std::shared_ptr<::HIR::ExprPtr> size;
- size_t size_val;
+ uint64_t size_val;
}),
(Slice, struct {
::std::unique_ptr<TypeRef> inner;
@@ -249,7 +277,7 @@ public:
TypeRef(::std::vector< ::HIR::TypeRef> sts):
m_data( Data::make_Tuple(mv$(sts)) )
{}
- TypeRef(::std::string name, unsigned int slot):
+ TypeRef(RcString name, unsigned int slot):
m_data( Data::make_Generic({ mv$(name), slot }) )
{}
TypeRef(::HIR::TypeRef::Data x):
@@ -316,6 +344,24 @@ public:
// Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x`
Compare compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const;
+
+ const ::HIR::SimplePath* get_sort_path() const {
+ // - Generic paths get sorted
+ if( TU_TEST1(this->m_data, Path, .path.m_data.is_Generic()) )
+ {
+ return &this->m_data.as_Path().path.m_data.as_Generic().m_path;
+ }
+ // - So do trait objects
+ else if( this->m_data.is_TraitObject() )
+ {
+ return &this->m_data.as_TraitObject().m_trait.m_path.m_path;
+ }
+ else
+ {
+ // Keep as nullptr, will search primitive list
+ return nullptr;
+ }
+ }
};
extern ::std::ostream& operator<<(::std::ostream& os, const ::HIR::TypeRef& ty);
diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp
index 2e03990a..664d34ad 100644
--- a/src/hir/visitor.cpp
+++ b/src/hir/visitor.cpp
@@ -12,21 +12,39 @@
{
}
+namespace {
+ template<typename T>
+ void visit_impls(::HIR::Crate::ImplGroup<T>& g, ::std::function<void(T&)> cb) {
+ for( auto& impl_group : g.named )
+ {
+ for( auto& impl : impl_group.second )
+ {
+ cb(*impl);
+ }
+ }
+ for( auto& impl : g.non_named )
+ {
+ cb(*impl);
+ }
+ for( auto& impl : g.generic )
+ {
+ cb(*impl);
+ }
+ }
+}
+
void ::HIR::Visitor::visit_crate(::HIR::Crate& crate)
{
this->visit_module(::HIR::ItemPath(crate.m_crate_name), crate.m_root_module );
- for( auto& ty_impl : crate.m_type_impls )
- {
- this->visit_type_impl(ty_impl);
- }
- for( auto& impl : crate.m_trait_impls )
+ visit_impls<::HIR::TypeImpl>(crate.m_type_impls, [&](::HIR::TypeImpl& ty_impl){ this->visit_type_impl(ty_impl); });
+ for( auto& impl_group : crate.m_trait_impls )
{
- this->visit_trait_impl(impl.first, impl.second);
+ visit_impls<::HIR::TraitImpl>(impl_group.second, [&](::HIR::TraitImpl& ty_impl){ this->visit_trait_impl(impl_group.first, ty_impl); });
}
- for( auto& impl : crate.m_marker_impls )
+ for( auto& impl_group : crate.m_marker_impls )
{
- this->visit_marker_impl(impl.first, impl.second);
+ visit_impls<::HIR::MarkerImpl>(impl_group.second, [&](::HIR::MarkerImpl& ty_impl){ this->visit_marker_impl(impl_group.first, ty_impl); });
}
}
@@ -47,6 +65,9 @@ void ::HIR::Visitor::visit_module(::HIR::ItemPath p, ::HIR::Module& mod)
DEBUG("type " << name);
this->visit_type_alias(p + name, e);
),
+ (ExternType,
+ DEBUG("extern type " << name);
+ ),
(Enum,
DEBUG("enum " << name);
this->visit_enum(p + name, e);
@@ -168,10 +189,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());
@@ -230,12 +250,21 @@ void ::HIR::Visitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item)
}
void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
for(auto& var : item.m_variants)
this->visit_type(var.second.ent);
}
+void ::HIR::Visitor::visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item)
+{
+ TRACE_FUNCTION_F(p);
+ 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)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
for(auto& arg : item.m_args)
{
@@ -247,11 +276,13 @@ void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item)
}
void ::HIR::Visitor::visit_static(::HIR::ItemPath p, ::HIR::Static& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_type(item.m_type);
this->visit_expr(item.m_value);
}
void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
this->visit_type(item.m_type);
this->visit_expr(item.m_value);
@@ -259,6 +290,7 @@ void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item)
void ::HIR::Visitor::visit_params(::HIR::GenericParams& params)
{
+ TRACE_FUNCTION_F(params.fmt_args() << params.fmt_bounds());
for(auto& tps : params.m_types)
this->visit_type( tps.m_default );
for(auto& bound : params.m_bounds )
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/bind.cpp b/src/hir_conv/bind.cpp
index 227ccd9f..e3441157 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -120,7 +120,7 @@ namespace {
m_cur_module.ptr = &mod;
m_cur_module.path = &p;
- m_ms.push_traits(mod);
+ m_ms.push_traits(p, mod);
::HIR::Visitor::visit_module(p, mod);
m_ms.pop_traits(mod);
@@ -140,6 +140,9 @@ namespace {
TU_MATCH(::HIR::Literal, (lit), (e),
(Invalid,
),
+ (Defer,
+ // Shouldn't happen here, but ...
+ ),
(List,
for(auto& val : e) {
visit_literal(sp, val);
@@ -253,17 +256,26 @@ namespace {
::HIR::Visitor::visit_pattern(pat);
- TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (e),
- (
- ),
- (Value,
+ TU_MATCH_HDRA( (pat.m_data), {)
+ default:
+ // Nothing
+ TU_ARMA(Value, e) {
this->visit_pattern_Value(sp, pat, e.val);
- ),
- (Range,
+ }
+ TU_ARMA(Range, e) {
this->visit_pattern_Value(sp, pat, e.start);
this->visit_pattern_Value(sp, pat, e.end);
- ),
- (StructTuple,
+ }
+ TU_ARMA(StructValue, e) {
+ const auto& str = get_struct_ptr(sp, m_crate, e.path);
+ TU_IFLET(::HIR::Struct::Data, str.m_data, Unit, _,
+ e.binding = &str;
+ )
+ else {
+ ERROR(sp, E0000, "Struct value pattern on non-unit struct " << e.path);
+ }
+ }
+ TU_ARMA(StructTuple, e) {
const auto& str = get_struct_ptr(sp, m_crate, e.path);
TU_IFLET(::HIR::Struct::Data, str.m_data, Tuple, _,
e.binding = &str;
@@ -271,8 +283,8 @@ namespace {
else {
ERROR(sp, E0000, "Struct tuple pattern on non-tuple struct " << e.path);
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
const auto& str = get_struct_ptr(sp, m_crate, e.path);
if(str.m_data.is_Named() ) {
}
@@ -284,8 +296,19 @@ namespace {
ERROR(sp, E0000, "Struct pattern `" << pat << "` on field-less struct " << e.path);
}
e.binding = &str;
- ),
- (EnumTuple,
+ }
+ TU_ARMA(EnumValue, e) {
+ auto p = get_enum_ptr(sp, m_crate, e.path);
+ if( p.first->m_data.is_Data() )
+ {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( var.is_struct || var.type != ::HIR::TypeRef::new_unit() )
+ ERROR(sp, E0000, "Enum value pattern on non-unit variant " << e.path);
+ }
+ e.binding_ptr = p.first;
+ e.binding_idx = p.second;
+ }
+ TU_ARMA(EnumTuple, e) {
auto p = get_enum_ptr(sp, m_crate, e.path);
if( !p.first->m_data.is_Data() )
ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path);
@@ -294,18 +317,61 @@ namespace {
ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path);
e.binding_ptr = p.first;
e.binding_idx = p.second;
- ),
- (EnumStruct,
+ }
+ TU_ARMA(EnumStruct, e) {
auto p = get_enum_ptr(sp, m_crate, e.path);
- if( !p.first->m_data.is_Data() )
- ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
- const auto& var = p.first->m_data.as_Data()[p.second];
- if( !var.is_struct )
- ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ if( !e.is_exhaustive && e.sub_patterns.empty() )
+ {
+ if( !p.first->m_data.is_Data() ) {
+ pat.m_data = ::HIR::Pattern::Data::make_EnumValue({
+ ::std::move(e.path), p.first, p.second
+ });
+ }
+ else {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( var.type == ::HIR::TypeRef::new_unit() )
+ {
+ pat.m_data = ::HIR::Pattern::Data::make_EnumValue({
+ ::std::move(e.path), p.first, p.second
+ });
+ }
+ else if( !var.is_struct )
+ {
+ ASSERT_BUG(sp, var.type.m_data.is_Path(), "");
+ ASSERT_BUG(sp, var.type.m_data.as_Path().binding.is_Struct(), "EnumStruct pattern on unexpected variant " << e.path << " with " << var.type.m_data.as_Path().binding.tag_str());
+ const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
+ ASSERT_BUG(sp, str.m_data.is_Tuple(), "");
+ const auto& flds = str.m_data.as_Tuple();
+ ::std::vector<HIR::Pattern> subpats;
+ for(size_t i = 0; i < flds.size(); i ++)
+ subpats.push_back(::HIR::Pattern { });
+ pat.m_data = ::HIR::Pattern::Data::make_EnumTuple({
+ ::std::move(e.path), p.first, p.second, mv$(subpats)
+ });
+ }
+ else
+ {
+ // Keep as a struct pattern
+ }
+ }
+ }
+ else
+ {
+ if( !p.first->m_data.is_Data() )
+ {
+ ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ }
+ else
+ {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( !var.is_struct )
+ ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ }
+ }
e.binding_ptr = p.first;
e.binding_idx = p.second;
- )
- )
+ }
+ }
}
static void fix_param_count(const Span& sp, const ::HIR::GenericPath& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params, bool fill_infer=true, const ::HIR::TypeRef* self_ty=nullptr)
{
@@ -314,6 +380,8 @@ namespace {
return ;
}
+ TRACE_FUNCTION_F(path);
+
if( params.m_types.size() == 0 && fill_infer ) {
for(const auto& typ : param_defs.m_types) {
(void)typ;
@@ -334,9 +402,20 @@ namespace {
auto ty = clone_ty_with(sp, typ.m_default, [&](const auto& ty, auto& out){
if(const auto* te = ty.m_data.opt_Generic() )
{
- if( te->binding != GENERIC_Self || !self_ty )
+ if( te->binding == GENERIC_Self ) {
+ if( !self_ty )
+ TODO(sp, "Self enountered in default params, but no Self available - " << ty << " in " << typ.m_default << " for " << path);
+ out = self_ty->clone();
+ }
+ // NOTE: Should only be seeing impl-level params here. Method-level ones are only seen in expression context.
+ else if( (te->binding >> 8) == 0 ) {
+ auto idx = te->binding & 0xFF;
+ ASSERT_BUG(sp, idx < params.m_types.size(), "TODO: Handle use of latter types in defaults");
+ out = params.m_types[idx].clone();
+ }
+ else {
TODO(sp, "Monomorphise in fix_param_count - encountered " << ty << " in " << typ.m_default);
- out = self_ty->clone();
+ }
return true;
}
return false;
@@ -377,6 +456,10 @@ namespace {
(TypeAlias,
BUG(sp, "TypeAlias encountered after `Resolve Type Aliases` - " << ty);
),
+ (ExternType,
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_ExternType(&e3);
+ DEBUG("- " << ty);
+ ),
(Struct,
fix_param_count(sp, pe, e3.m_params, pe.m_params);
e.binding = ::HIR::TypeRef::TypePathBinding::make_Struct(&e3);
@@ -429,12 +512,16 @@ namespace {
void visit_type_impl(::HIR::TypeImpl& impl) override
{
- TRACE_FUNCTION_F("impl " << impl.m_type);
+ TRACE_FUNCTION_F("impl " << impl.m_type << " - from " << impl.m_src_module);
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
::HIR::Visitor::visit_type_impl(impl);
if(mod)
m_ms.pop_traits(*mod);
@@ -444,9 +531,13 @@ namespace {
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type);
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) );
::HIR::Visitor::visit_trait_impl(trait_path, impl);
m_ms.m_traits.pop_back( );
@@ -458,9 +549,13 @@ namespace {
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }");
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
::HIR::Visitor::visit_marker_impl(trait_path, impl);
if(mod)
m_ms.pop_traits(*mod);
@@ -566,7 +661,7 @@ namespace {
void visit(::HIR::ExprNode_StructLiteral& node) override
{
- upper_visitor.visit_generic_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
+ upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
::HIR::ExprVisitorDef::visit(node);
}
void visit(::HIR::ExprNode_ArraySized& node) override
@@ -609,28 +704,24 @@ namespace {
struct H {
static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Local,
- ),
- (Argument,
- ),
- (Static,
- upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE);
- ),
- (Field,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Deref,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Index,
- H::visit_lvalue(upper_visitor, *e.val);
- H::visit_lvalue(upper_visitor, *e.idx);
+ if( lv.m_root.is_Static() ) {
+ upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE);
+ }
+ }
+ static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e)
+ {
+ TU_MATCHA( (e), (ce),
+ (Int, ),
+ (Uint,),
+ (Float, ),
+ (Bool, ),
+ (Bytes, ),
+ (StaticString, ), // String
+ (Const,
+ upper_visitor.visit_path(*ce.p, ::HIR::Visitor::PathContext::VALUE);
),
- (Downcast,
- H::visit_lvalue(upper_visitor, *e.val);
+ (ItemAddr,
+ upper_visitor.visit_path(*ce, ::HIR::Visitor::PathContext::VALUE);
)
)
}
@@ -639,20 +730,7 @@ namespace {
TU_MATCHA( (p), (e),
(LValue, H::visit_lvalue(upper_visitor, e);),
(Constant,
- TU_MATCHA( (e), (ce),
- (Int, ),
- (Uint,),
- (Float, ),
- (Bool, ),
- (Bytes, ),
- (StaticString, ), // String
- (Const,
- upper_visitor.visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE);
- ),
- (ItemAddr,
- upper_visitor.visit_path(ce, ::HIR::Visitor::PathContext::VALUE);
- )
- )
+ H::visit_constant(upper_visitor, e);
)
)
}
@@ -670,20 +748,7 @@ namespace {
H::visit_lvalue(*this, e);
),
(Constant,
- TU_MATCHA( (e), (ce),
- (Int, ),
- (Uint,),
- (Float, ),
- (Bool, ),
- (Bytes, ),
- (StaticString, ), // String
- (Const,
- this->visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE);
- ),
- (ItemAddr,
- this->visit_path(ce, ::HIR::Visitor::PathContext::VALUE);
- )
- )
+ H::visit_constant(*this, e);
),
(SizedArray,
H::visit_param(*this, e.val);
@@ -779,11 +844,12 @@ namespace {
void ConvertHIR_Bind(::HIR::Crate& crate)
{
Visitor exp { crate };
- exp.visit_crate( crate );
// Also visit extern crates to update their pointers
for(auto& ec : crate.m_ext_crates)
{
exp.visit_crate( *ec.second.m_data );
}
+
+ exp.visit_crate( crate );
}
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp
index ec313e4a..35669dd9 100644
--- a/src/hir_conv/constant_evaluation.cpp
+++ b/src/hir_conv/constant_evaluation.cpp
@@ -16,8 +16,15 @@
#include <trans/target.hpp>
#include <hir/expr_state.hpp>
+#include "constant_evaluation.hpp"
+#include <trans/monomorphise.hpp> // For handling monomorph of MIR in provided associated constants
+
+#define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0)
+
namespace {
- struct NewvalState {
+ struct NewvalState
+ : public HIR::Evaluator::Newval
+ {
const ::HIR::Module& mod;
const ::HIR::ItemPath& mod_path;
::std::string name_prefix;
@@ -31,9 +38,9 @@ namespace {
{
}
- ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value)
+ virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override
{
- auto name = FMT(name_prefix << next_item_idx);
+ auto name = RcString::new_interned(FMT(name_prefix << next_item_idx));
next_item_idx ++;
DEBUG("mod_path = " << mod_path);
auto rv = mod_path.get_simple_path() + name.c_str();
@@ -47,23 +54,6 @@ namespace {
return rv;
}
};
- struct Evaluator
- {
- const Span& root_span;
- StaticTraitResolve resolve;
- NewvalState nvs;
-
- Evaluator(const Span& sp, const ::HIR::Crate& crate, NewvalState nvs):
- root_span(sp),
- resolve(crate),
- nvs( ::std::move(nvs) )
- {
- }
-
- ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp);
-
- ::HIR::Literal evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args);
- };
::HIR::Literal clone_literal(const ::HIR::Literal& v)
{
@@ -71,6 +61,9 @@ namespace {
(Invalid,
return ::HIR::Literal();
),
+ (Defer,
+ return ::HIR::Literal::make_Defer({});
+ ),
(List,
::std::vector< ::HIR::Literal> vals;
for(const auto& val : e) {
@@ -162,6 +155,8 @@ namespace {
),
(Enum,
),
+ (ExternType,
+ ),
(TypeAlias,
)
)
@@ -267,13 +262,16 @@ namespace {
TODO(sp, "Could not find function for " << path << " - " << rv.tag_str());
}
}
+} // namespace <anon>
+
+namespace HIR {
- ::HIR::Literal Evaluator::evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args)
+ ::HIR::Literal Evaluator::evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args)
{
// TODO: Full-blown miri
TRACE_FUNCTION_F("exp=" << exp << ", args=" << args);
- ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(,), exp, {}, fcn };
+ ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(ss, ss<<ip), exp, {}, fcn };
::HIR::Literal retval;
::std::vector< ::HIR::Literal> locals( fcn.locals.size() );
@@ -295,61 +293,66 @@ namespace {
::HIR::Literal& get_lval(const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
+ ::HIR::Literal* lit_ptr;
+ TRACE_FUNCTION_FR(lv, *lit_ptr);
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return retval;
+ lit_ptr = &retval;
),
(Local,
- if( e >= locals.size() )
- MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size());
- return locals[e];
+ MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size());
+ lit_ptr = &locals[e];
),
(Argument,
- if( e.idx >= args.size() )
- MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size());
- return args[e.idx];
+ MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size());
+ lit_ptr = &args[e];
),
(Static,
MIR_TODO(state, "LValue::Static - " << e);
- ),
- (Field,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range");
- return vals[ e.field_index ];
- ),
- (Deref,
- auto& val = get_lval(*e.val);
- TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
- (
- MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
- ),
- (BorrowData,
- return *ve;
- ),
- (String,
- // Just clone the string (hack)
- // - TODO: Create a list?
- return val;
- )
- )
- ),
- (Index,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
- auto& idx = get_lval(*e.idx);
- MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- auto idx_v = static_cast<size_t>( idx.as_Integer() );
- MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
- return vals[ idx_v ];
- ),
- (Downcast,
- MIR_TODO(state, "LValue::Downcast - " << lv);
)
)
- throw "";
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& val = *lit_ptr;
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ MIR_ASSERT(state, e < vals.size(), "LValue::Field index out of range");
+ lit_ptr = &vals[ e ];
+ }
+ TU_ARMA(Deref, e) {
+ TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
+ (
+ MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
+ ),
+ (BorrowData,
+ lit_ptr = &*ve;
+ ),
+ (String,
+ // Just clone the string (hack)
+ // - TODO: Create a list?
+ lit_ptr = &val;
+ )
+ )
+ }
+ TU_ARMA(Index, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
+ MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range");
+ auto& idx = locals[e];
+ MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ auto idx_v = static_cast<size_t>( idx.as_Integer() );
+ MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
+ lit_ptr = &vals[ idx_v ];
+ }
+ TU_ARMA(Downcast, e) {
+ MIR_TODO(state, "LValue::Downcast - " << lv);
+ }
+ }
+ }
+ return *lit_ptr;
}
::HIR::Literal read_lval(const ::MIR::LValue& lv)
{
@@ -377,27 +380,28 @@ namespace {
LocalState local_state( state, retval, args, locals );
auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal {
- TU_MATCH(::MIR::Constant, (c), (e2),
- (Int,
+ TU_MATCH_HDR( (c), {)
+ TU_ARM(c, Int, e2) {
return ::HIR::Literal(static_cast<uint64_t>(e2.v));
- ),
- (Uint,
+ }
+ TU_ARM(c, Uint, e2)
return ::HIR::Literal(e2.v);
- ),
- (Float,
+ TU_ARM(c, Float, e2)
return ::HIR::Literal(e2.v);
- ),
- (Bool,
+ TU_ARM(c, Bool, e2)
return ::HIR::Literal(static_cast<uint64_t>(e2.v));
- ),
- (Bytes,
+ TU_ARM(c, Bytes, e2)
return ::HIR::Literal::make_String({e2.begin(), e2.end()});
- ),
- (StaticString,
+ TU_ARM(c, StaticString, e2)
return ::HIR::Literal(e2);
- ),
- (Const,
- auto p = ms.monomorph(state.sp, e2.p);
+ TU_ARM(c, Const, e2) {
+ auto p = ms.monomorph(state.sp, *e2.p);
+ // If there's any mention of generics in this path, then return Literal::Defer
+ if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) )
+ {
+ DEBUG("Return Literal::Defer for constant " << *e2.p << " which references a generic parameter");
+ return ::HIR::Literal::make_Defer({});
+ }
MonomorphState const_ms;
auto ent = get_ent_fullpath(state.sp, this->resolve.m_crate, p, EntNS::Value, const_ms);
MIR_ASSERT(state, ent.is_Constant(), "MIR Constant::Const(" << p << ") didn't point to a Constant - " << ent.tag_str());
@@ -407,19 +411,25 @@ namespace {
auto& item = const_cast<::HIR::Constant&>(c);
// Challenge: Adding items to the module might invalidate an iterator.
::HIR::ItemPath mod_ip { item.m_value.m_state->m_mod_path };
- auto eval = Evaluator { item.m_value->span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } };
+ auto nvs = NewvalState { item.m_value.m_state->m_module, mod_ip, FMT("const" << &c << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value.span(), resolve.m_crate, nvs };
DEBUG("- Evaluate " << p);
DEBUG("- " << ::HIR::ItemPath(p));
item.m_value_res = eval.evaluate_constant(::HIR::ItemPath(p), item.m_value, item.m_type.clone());
//check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
}
+ auto it = c.m_monomorph_cache.find(*e2.p);
+ if( it != c.m_monomorph_cache.end() )
+ {
+ MIR_ASSERT(state, !it->second.is_Defer(), "Cached literal for " << *e2.p << " is Defer");
+ return clone_literal( it->second );
+ }
return clone_literal( c.m_value_res );
- ),
- (ItemAddr,
- return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) );
- )
- )
+ }
+ TU_ARM(c, ItemAddr, e2)
+ return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, *e2) );
+ }
throw "";
};
auto read_param = [&](const ::MIR::Param& p) -> ::HIR::Literal
@@ -476,17 +486,14 @@ namespace {
MIR_BUG(state, "Only shared borrows are allowed in constants");
}
- if( e.type != ::HIR::BorrowType::Shared ) {
- MIR_BUG(state, "Only shared borrows are allowed in constants");
+ if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) {
+ //if( p->val->is_Deref() )
+ // MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
+ val = local_state.read_lval(e.val.clone_unwrapped());
}
- if( const auto* p = e.val.opt_Deref() ) {
- if( p->val->is_Deref() )
- MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
- val = local_state.read_lval(*p->val);
- }
- else if( const auto* p = e.val.opt_Static() ) {
+ else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){
// Borrow of a static, emit BorrowPath with the same path
- val = ::HIR::Literal::make_BorrowPath( p->clone() );
+ val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() );
}
else {
auto inner_val = local_state.read_lval(e.val);
@@ -504,6 +511,10 @@ namespace {
),
(Cast,
auto inval = local_state.read_lval(e.val);
+ if( inval.is_Defer() ) {
+ val = ::HIR::Literal::make_Defer({});
+ }
+ else
TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te),
(
// NOTE: Can be an unsizing!
@@ -585,6 +596,8 @@ namespace {
(BinOp,
auto inval_l = read_param(e.val_l);
auto inval_r = read_param(e.val_r);
+ if( inval_l.is_Defer() || inval_r.is_Defer() )
+ return ::HIR::Literal::make_Defer({});
MIR_ASSERT(state, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r);
TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r),
(
@@ -651,6 +664,8 @@ namespace {
),
(UniOp,
auto inval = local_state.read_lval(e.val);
+ if( inval.is_Defer() )
+ return ::HIR::Literal::make_Defer({});
TU_IFLET( ::HIR::Literal, inval, Integer, i,
switch( e.op )
{
@@ -685,7 +700,9 @@ namespace {
),
(MakeDst,
auto ptr = read_param(e.ptr_val);
+ if(ptr.is_Defer()) return ::HIR::Literal::make_Defer({});
auto meta = read_param(e.meta_val);
+ if(meta.is_Defer()) return ::HIR::Literal::make_Defer({});
if( ! meta.is_Integer() ) {
MIR_TODO(state, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta);
}
@@ -696,26 +713,39 @@ namespace {
(Tuple,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
),
(Array,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
),
(Variant,
auto ival = read_param(e.val);
+ if(ival.is_Defer()) return ::HIR::Literal::make_Defer({});
val = ::HIR::Literal::make_Variant({ e.index, box$(ival) });
),
(Struct,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
)
)
@@ -724,15 +754,18 @@ namespace {
dst = mv$(val);
}
state.set_cur_stmt_term(cur_block);
- TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e),
- (
+ TU_MATCH_HDRA( (block.terminator), {)
+ default:
MIR_BUG(state, "Unexpected terminator - " << block.terminator);
- ),
- (Goto,
+ TU_ARMA(Goto, e) {
cur_block = e;
- ),
- (Return,
- if( exp.m_data.is_Primitive() )
+ }
+ TU_ARMA(Return, e) {
+ if( retval.is_Defer() )
+ {
+ //
+ }
+ else if( exp.m_data.is_Primitive() )
{
switch( exp.m_data.as_Primitive() )
{
@@ -773,52 +806,81 @@ namespace {
}
}
return retval;
- ),
- (Call,
- if( !e.fcn.is_Path() )
- MIR_BUG(state, "Unexpected terminator - " << block.terminator);
- const auto& fcnp_raw = e.fcn.as_Path();
- auto fcnp = ms.monomorph(state.sp, fcnp_raw);
-
+ }
+ TU_ARMA(Call, e) {
auto& dst = local_state.get_lval(e.ret_val);
- MonomorphState fcn_ms;
- auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms);
+ if( const auto* te = e.fcn.opt_Intrinsic() )
+ {
+ if( te->name == "size_of" ) {
+ auto ty = ms.monomorph(state.sp, te->params.m_types.at(0));
+ size_t size_val;
+ Target_GetSizeOf(state.sp, this->resolve, ty, size_val);
+ dst = ::HIR::Literal::make_Integer( size_val );
+ }
+ else {
+ MIR_TODO(state, "Call intrinsic \"" << te->name << "\" - " << block.terminator);
+ }
+ }
+ else if( const auto* te = e.fcn.opt_Path() )
+ {
+ const auto& fcnp_raw = *te;
+ auto fcnp = ms.monomorph(state.sp, fcnp_raw);
- ::std::vector< ::HIR::Literal> call_args;
- call_args.reserve( e.args.size() );
- for(const auto& a : e.args)
- call_args.push_back( read_param(a) );
- // TODO: Set m_const during parse and check here
+ MonomorphState fcn_ms;
+ auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms);
- // Call by invoking evaluate_constant on the function
+ ::std::vector< ::HIR::Literal> call_args;
+ call_args.reserve( e.args.size() );
+ for(const auto& a : e.args)
+ call_args.push_back( read_param(a) );
+ // TODO: Set m_const during parse and check here
+
+ // Call by invoking evaluate_constant on the function
+ {
+ TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }");
+ auto fcn_ip = ::HIR::ItemPath(fcnp);
+ const auto* mir = this->resolve.m_crate.get_or_gen_mir( fcn_ip, fcn );
+ MIR_ASSERT(state, mir, "No MIR for function " << fcnp);
+ dst = evaluate_constant_mir(fcn_ip, *mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args));
+ }
+ }
+ else
{
- TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }");
- const auto* mir = this->resolve.m_crate.get_or_gen_mir( ::HIR::ItemPath(fcnp.clone()), fcn );
- MIR_ASSERT(state, mir, "No MIR for function " << fcnp);
- dst = evaluate_constant_mir(*mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args));
+ MIR_BUG(state, "Unexpected terminator - " << block.terminator);
}
-
cur_block = e.ret_block;
- )
- )
+ }
+ }
}
}
- ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp)
+ ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms/*={}*/)
{
TRACE_FUNCTION_F(ip);
const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp);
if( mir ) {
- return evaluate_constant_mir(*mir, {}, mv$(exp), {});
+ ::HIR::TypeRef ty_self { "Self", GENERIC_Self };
+ // Might want to have a fully-populated MonomorphState for expanding inside impl blocks
+ // HACK: Generate a roughly-correct one
+ const auto& top_ip = ip.get_top_ip();
+ if( top_ip.trait && !top_ip.ty ) {
+ ms.self_ty = &ty_self;
+ }
+ return evaluate_constant_mir(ip, *mir, mv$(ms), mv$(exp), {});
}
else {
BUG(this->root_span, "Attempting to evaluate constant expression with no associated code");
}
}
+} // namespace HIR
+
+namespace {
void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit)
{
+ if( lit.is_Defer() )
+ return ;
// TODO: Mask down limited size integers
TU_MATCHA( (type.m_data), (te),
(Infer,
@@ -898,12 +960,15 @@ namespace {
const ::HIR::Crate& m_crate;
const ::HIR::Module* m_mod;
const ::HIR::ItemPath* m_mod_path;
+ MonomorphState m_monomorph_state;
+ bool m_recurse_types;
public:
Expander(const ::HIR::Crate& crate):
m_crate(crate),
m_mod(nullptr),
m_mod_path(nullptr)
+ ,m_recurse_types(false)
{}
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
@@ -918,20 +983,123 @@ namespace {
m_mod = saved_m;
m_mod_path = saved_mp;
}
+ void visit_function(::HIR::ItemPath p, ::HIR::Function& f) override
+ {
+ TRACE_FUNCTION_F(p);
+ ::HIR::Visitor::visit_function(p, f);
+ }
+
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override
+ {
+ static Span sp;
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type);
+ const auto& trait = m_crate.get_trait_by_path(sp, trait_path);
+
+ StaticTraitResolve resolve( m_crate );
+ // - TODO: Defer this call until first missing item?
+ resolve.set_impl_generics(impl.m_params);
+
+ auto mp = ::HIR::ItemPath(impl.m_src_module);
+ m_mod_path = &mp;
+ m_mod = &m_crate.get_mod_by_path(sp, impl.m_src_module);
+
+ for(const auto& vi : trait.m_values)
+ {
+ // Search for any constants that are in the trait itself, but NOT in this impl
+ // - For each of these, find the lowest parent specialisation with the constant set
+ // - Ensure that the MIR has been generated for the constant (TODO: This only needs to be done for
+ // specialisations, not trait-provided)
+ // - Monomorphise the MIR for this impl, and let expansion happen as usual
+ if( vi.second.is_Constant() )
+ {
+ if( impl.m_constants.count(vi.first) > 0 )
+ continue;
+ DEBUG("- Constant " << vi.first << " missing, looking for a source");
+ // This trait impl doesn't have this constant, need to find the provided version that applies
+
+ MonomorphState ms;
+ ms.self_ty = &impl.m_type;
+ ms.pp_impl = &impl.m_trait_args;
+
+ resolve.find_impl(sp, trait_path, impl.m_trait_args, impl.m_type, [&](ImplRef found_impl, bool is_fuzzed)->bool {
+ ASSERT_BUG(sp, found_impl.m_data.is_TraitImpl(), "");
+ // If this found impl is the current one, keep searching
+ if( found_impl.m_data.as_TraitImpl().impl == &impl )
+ return false;
+ TODO(sp, "Found a possible parent specialisation of " << trait_path << impl.m_trait_args << " for " << impl.m_type << " - " << found_impl);
+ return false;
+ });
+ const auto& template_const = vi.second.as_Constant();
+ if( template_const.m_value_res.is_Defer() ) {
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "_" << vi.first << "#") };
+ auto eval = ::HIR::Evaluator { sp, m_crate, nvs };
+ ::HIR::ExprPtr ep;
+ Trans_Params tp(sp);
+ tp.self_type = ms.self_ty->clone();
+ tp.pp_impl = ms.pp_impl->clone();
+ ep.m_mir = Trans_Monomorphise(resolve, mv$(tp), template_const.m_value.m_mir);
+ ep.m_state = ::HIR::ExprStatePtr( ::HIR::ExprState(*m_mod, m_mod_path->get_simple_path()) );
+ DEBUG("TMP TMP " << trait_path << " - " << ep.m_state->m_mod_path);
+ ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
+ impl.m_constants.insert(::std::make_pair(
+ vi.first,
+ ::HIR::TraitImpl::ImplEnt<::HIR::Constant> {
+ /*is_specialisable=*/false,
+ ::HIR::Constant {
+ template_const.m_params.clone(),
+ /*m_type=*/ms.monomorph(sp, template_const.m_type),
+ /*m_value=*/mv$(ep),
+ ::HIR::Literal()
+ }
+ }
+ ));
+ }
+ else {
+ //TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type);
+ impl.m_constants.insert(::std::make_pair(
+ vi.first,
+ ::HIR::TraitImpl::ImplEnt<::HIR::Constant> {
+ /*is_specialisable=*/false,
+ ::HIR::Constant {
+ template_const.m_params.clone(),
+ /*m_type=*/ms.monomorph(sp, template_const.m_type),
+ /*m_value=*/::HIR::ExprPtr(),
+ clone_literal(template_const.m_value_res)
+ }
+ }
+ ));
+ }
+ }
+ }
+
+ ::HIR::PathParams pp_impl;
+ for(const auto& tp : impl.m_params.m_types)
+ pp_impl.m_types.push_back( ::HIR::TypeRef(tp.m_name, pp_impl.m_types.size() | 256) );
+ m_monomorph_state.pp_impl = &pp_impl;
+
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+
+ m_monomorph_state.pp_impl = nullptr;
+
+ m_mod = nullptr;
+ m_mod_path = nullptr;
+ }
void visit_type(::HIR::TypeRef& ty) override
{
::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);
assert(*e.size);
const auto& expr_ptr = *e.size;
- auto ty_name = FMT("ty_" << &ty << "$");
+ auto ty_name = FMT("ty_" << &ty << "#");
- auto eval = Evaluator { expr_ptr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, ty_name } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, ty_name };
+ auto eval = ::HIR::Evaluator { expr_ptr->span(), m_crate, nvs };
auto val = eval.evaluate_constant(::HIR::ItemPath(*m_mod_path, ty_name.c_str()), expr_ptr, ::HIR::CoreType::Usize);
if( !val.is_Integer() )
ERROR(expr_ptr->span(), E0000, "Array size isn't an integer");
@@ -939,29 +1107,60 @@ namespace {
}
DEBUG("Array " << ty << " - size = " << e.size_val);
)
+
+ if( m_recurse_types )
+ {
+ m_recurse_types = false;
+ if( const auto* te = ty.m_data.opt_Path() )
+ {
+ TU_MATCH_HDRA( (te->binding), {)
+ TU_ARMA(Unbound, _) {
+ }
+ TU_ARMA(Opaque, _) {
+ }
+ TU_ARMA(Struct, pbe) {
+ // If this struct hasn't been visited already, visit it
+ this->visit_struct(te->path.m_data.as_Generic().m_path, const_cast<::HIR::Struct&>(*pbe));
+ }
+ TU_ARMA(Union, pbe) {
+ }
+ TU_ARMA(Enum, pbe) {
+ }
+ TU_ARMA(ExternType, pbe) {
+ }
+ }
+ }
+ m_recurse_types = true;
+ }
}
void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override
{
+ m_recurse_types = true;
::HIR::Visitor::visit_constant(p, item);
+ m_recurse_types = false;
// NOTE: Consteval needed here for MIR match generation to work
- if( item.m_value )
+ if( item.m_value || item.m_value.m_mir )
{
- auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } };
- item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone());
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value.span(), m_crate, nvs };
+ item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone(), m_monomorph_state.clone());
- check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
+ check_lit_type(item.m_value.span(), item.m_type, item.m_value_res);
DEBUG("constant: " << item.m_type << " = " << item.m_value_res);
}
}
void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override
{
+ m_recurse_types = true;
::HIR::Visitor::visit_static(p, item);
+ m_recurse_types = false;
if( item.m_value )
{
- auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value->span(), m_crate, nvs };
item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone());
check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
@@ -970,6 +1169,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;
@@ -978,7 +1178,8 @@ namespace {
{
if( var.expr )
{
- auto eval = Evaluator { var.expr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "_" << var.name << "#") };
+ auto eval = ::HIR::Evaluator { var.expr->span(), m_crate, nvs };
auto val = eval.evaluate_constant(p, var.expr, ty.clone());
DEBUG("enum variant: " << p << "::" << var.name << " = " << val);
i = val.as_Integer();
@@ -989,6 +1190,15 @@ namespace {
}
::HIR::Visitor::visit_enum(p, item);
}
+ void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override {
+ if( item.const_eval_state != HIR::ConstEvalState::Complete )
+ {
+ ASSERT_BUG(Span(), item.const_eval_state == HIR::ConstEvalState::None, "Constant evaluation loop involving " << p);
+ item.const_eval_state = HIR::ConstEvalState::Active;
+ ::HIR::Visitor::visit_struct(p, item);
+ item.const_eval_state = HIR::ConstEvalState::Complete;
+ }
+ }
void visit_expr(::HIR::ExprPtr& expr) override
{
@@ -1003,6 +1213,7 @@ namespace {
void visit_type(::HIR::TypeRef& ty) override {
// Need to evaluate array sizes
+ DEBUG("expr type " << ty);
m_exp.visit_type(ty);
}
void visit_path_params(::HIR::PathParams& pp) override {
@@ -1012,8 +1223,9 @@ namespace {
void visit(::HIR::ExprNode_ArraySized& node) override {
assert( node.m_size );
- auto name = FMT("array_" << &node << "$");
- auto eval = Evaluator { node.span(), m_exp.m_crate, NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name } };
+ auto name = FMT("array_" << &node << "#");
+ auto nvs = NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name };
+ auto eval = ::HIR::Evaluator { node.span(), m_exp.m_crate, nvs };
auto val = eval.evaluate_constant( ::HIR::ItemPath(*m_exp.m_mod_path, name.c_str()), node.m_size, ::HIR::CoreType::Usize );
if( !val.is_Integer() )
ERROR(node.span(), E0000, "Array size isn't an integer");
@@ -1025,7 +1237,9 @@ namespace {
if( expr.get() != nullptr )
{
Visitor v { *this };
+ //m_recurse_types = true;
(*expr).visit(v);
+ //m_recurse_types = false;
}
}
};
@@ -1047,7 +1261,7 @@ namespace {
{
// ::std::unique_ptr<VisEnt<ValueItem>>
::std::unique_ptr<::HIR::VisEnt<::HIR::ValueItem>> iv;
- iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem::make_Static(mv$(v.second)) } );
+ iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { ::HIR::Publicity::new_none(), ::HIR::ValueItem::make_Static(mv$(v.second)) } );
mod.m_value_items.insert(::std::make_pair( v.first, mv$(iv) ));
}
mod.m_inline_statics.clear();
@@ -1066,3 +1280,10 @@ void ConvertHIR_ConstantEvaluate(::HIR::Crate& crate)
ExpanderApply().visit_crate(crate);
}
+void ConvertHIR_ConstantEvaluate_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip, ::HIR::ExprPtr& expr_ptr)
+{
+ TRACE_FUNCTION_F(ip);
+ // Check innards but NOT the value
+ Expander exp { crate };
+ exp.visit_expr( expr_ptr );
+}
diff --git a/src/hir_conv/constant_evaluation.hpp b/src/hir_conv/constant_evaluation.hpp
new file mode 100644
index 00000000..a5fd7050
--- /dev/null
+++ b/src/hir_conv/constant_evaluation.hpp
@@ -0,0 +1,33 @@
+/*
+ */
+#include <hir/hir.hpp>
+
+namespace HIR {
+
+
+struct Evaluator
+{
+ class Newval
+ {
+ public:
+ virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) = 0;
+ };
+
+ Span root_span;
+ StaticTraitResolve resolve;
+ Newval& nvs;
+
+ Evaluator(const Span& sp, const ::HIR::Crate& crate, Newval& nvs):
+ root_span(sp),
+ resolve(crate),
+ nvs( nvs )
+ {
+ }
+
+ ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms={});
+
+ ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args);
+};
+
+} // namespace HIR
+
diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp
index dcdf79bd..2dfffb73 100644
--- a/src/hir_conv/expand_type.cpp
+++ b/src/hir_conv/expand_type.cpp
@@ -21,8 +21,14 @@
// Anything else - leave it be
),
(TypeAlias,
- if( !is_expr && path.m_params.m_types.size() != e2.m_params.m_types.size() ) {
- ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << path.m_params.m_types.size());
+ auto pp = path.m_params.clone();
+ if( !is_expr ) {
+ while( pp.m_types.size() < e2.m_params.m_types.size() && e2.m_params.m_types[pp.m_types.size()].m_default != ::HIR::TypeRef() ) {
+ pp.m_types.push_back( e2.m_params.m_types[pp.m_types.size()].m_default.clone() );
+ }
+ if( pp.m_types.size() != e2.m_params.m_types.size() ) {
+ ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << pp.m_types.size());
+ }
}
if( e2.m_params.m_types.size() > 0 ) {
// TODO: Better `monomorphise_type`
@@ -33,8 +39,8 @@
}
else if( (ge.binding >> 8) == 0 ) {
auto idx = ge.binding & 0xFF;
- if( idx < path.m_params.m_types.size() )
- return path.m_params.m_types[idx];
+ if( idx < pp.m_types.size() )
+ return pp.m_types[idx];
else if( is_expr )
return empty_type;
else
@@ -255,9 +261,10 @@ public:
{
if( node.m_is_struct )
{
- auto new_path = upper_visitor.expand_alias_gp(node.span(), node.m_path);
- if( new_path.m_path.m_components.size() != 0 )
+ auto new_type = ConvertHIR_ExpandAliases_GetExpansion(upper_visitor.m_crate, node.m_path, /*in_expr=*/true);
+ if( new_type != ::HIR::TypeRef() )
{
+ auto new_path = mv$(new_type.m_data.as_Path().path);
DEBUG("Replacing " << node.m_path << " with " << new_path);
node.m_path = mv$(new_path);
}
diff --git a/src/hir_conv/main_bindings.hpp b/src/hir_conv/main_bindings.hpp
index 37488dae..a7bc9de6 100644
--- a/src/hir_conv/main_bindings.hpp
+++ b/src/hir_conv/main_bindings.hpp
@@ -9,10 +9,16 @@
namespace HIR {
class Crate;
+ class ItemPath;
+ class ExprPtr;
};
extern void ConvertHIR_ExpandAliases(::HIR::Crate& crate);
extern void ConvertHIR_Bind(::HIR::Crate& crate);
+extern void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate);
extern void ConvertHIR_ResolveUFCS(::HIR::Crate& crate);
extern void ConvertHIR_Markings(::HIR::Crate& crate);
extern void ConvertHIR_ConstantEvaluate(::HIR::Crate& hir_crate);
+
+extern void ConvertHIR_ConstantEvaluate_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip, ::HIR::ExprPtr& exp);
+
diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp
index df7fbd36..01eb0952 100644
--- a/src/hir_conv/markings.cpp
+++ b/src/hir_conv/markings.cpp
@@ -20,6 +20,7 @@ class Visitor:
const ::HIR::Crate& m_crate;
const ::HIR::SimplePath& m_lang_Unsize;
const ::HIR::SimplePath& m_lang_CoerceUnsized;
+ const ::HIR::SimplePath& m_lang_Copy;
const ::HIR::SimplePath& m_lang_Deref;
const ::HIR::SimplePath& m_lang_Drop;
const ::HIR::SimplePath& m_lang_PhantomData;
@@ -28,6 +29,7 @@ public:
m_crate(crate),
m_lang_Unsize( crate.get_lang_item_path_opt("unsize") ),
m_lang_CoerceUnsized( crate.get_lang_item_path_opt("coerce_unsized") ),
+ m_lang_Copy( crate.get_lang_item_path_opt("copy") ),
m_lang_Deref( crate.get_lang_item_path_opt("deref") ),
m_lang_Drop( crate.get_lang_item_path_opt("drop") ),
m_lang_PhantomData( crate.get_lang_item_path_opt("phantom_data") )
@@ -329,14 +331,7 @@ public:
if( impl.m_type.m_data.is_Path() )
{
const auto& te = impl.m_type.m_data.as_Path();
- const ::HIR::TraitMarkings* markings_ptr = nullptr;
- TU_MATCHA( (te.binding), (tpb),
- (Unbound, ),
- (Opaque, ),
- (Struct, markings_ptr = &tpb->m_markings; ),
- (Union , markings_ptr = &tpb->m_markings; ),
- (Enum , markings_ptr = &tpb->m_markings; )
- )
+ const ::HIR::TraitMarkings* markings_ptr = te.binding.get_trait_markings();
if( markings_ptr )
{
::HIR::TraitMarkings& markings = *const_cast<::HIR::TraitMarkings*>(markings_ptr);
@@ -434,6 +429,10 @@ public:
DEBUG("Type " << impl.m_type << " can Deref");
markings.has_a_deref = true;
}
+ else if( trait_path == m_lang_Copy ) {
+ DEBUG("Type " << impl.m_type << " has a Copy impl");
+ markings.is_copy = true;
+ }
// TODO: Marker traits (with conditions)
else {
}
diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp
index 55fbf593..90b3868d 100644
--- a/src/hir_conv/resolve_ufcs.cpp
+++ b/src/hir_conv/resolve_ufcs.cpp
@@ -5,6 +5,10 @@
* hir_conv/resolve_ufcs.cpp
* - Resolve unkown UFCS traits into inherent or trait
* - HACK: Will likely be replaced with a proper typeck pass (no it won't)
+ *
+ * TODO: Remove this pass, except maybe for running EAT on outer types
+ * - Expression code can handle picking UFCS functions better than this code can
+ * - Outer EAT is nice, but StaticTraitResolve will need to handle non-EAT-ed types when doing lookups
*/
#include "main_bindings.hpp"
#include <hir/hir.hpp>
@@ -91,11 +95,37 @@ namespace {
auto _g = m_resolve.set_impl_generics(impl.m_params);
::HIR::Visitor::visit_type_impl(impl);
}
+ void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+ auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) );
+ auto _g = m_resolve.set_impl_generics(impl.m_params);
+
+ // TODO: Push a bound that `Self: ThisTrait`
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ // The implemented trait is always in scope
+ m_traits.push_back( ::std::make_pair( &trait_path, m_current_trait) );
+ ::HIR::Visitor::visit_marker_impl(trait_path, impl);
+ m_traits.pop_back( );
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ }
void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override {
::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) );
auto _g = m_resolve.set_impl_generics(impl.m_params);
+ // TODO: Handle resolution of all items in m_resolve.m_type_equalities
+ // - params might reference each other, so `set_item_generics` has to have been called
+ // - But `m_type_equalities` can end up with non-resolved UFCS paths
+ for(auto& e : m_resolve.m_type_equalities)
+ {
+ visit_type(e.second);
+ }
// TODO: Push a bound that `Self: ThisTrait`
m_current_type = &impl.m_type;
@@ -157,6 +187,11 @@ namespace {
upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE);
::HIR::ExprVisitorDef::visit(node);
}
+ void visit(::HIR::ExprNode_StructLiteral& node) override
+ {
+ upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
+ ::HIR::ExprVisitorDef::visit(node);
+ }
void visit(::HIR::ExprNode_Match& node) override
{
diff --git a/src/hir_conv/resolve_ufcs_outer.cpp b/src/hir_conv/resolve_ufcs_outer.cpp
new file mode 100644
index 00000000..4e90f4f2
--- /dev/null
+++ b/src/hir_conv/resolve_ufcs_outer.cpp
@@ -0,0 +1,384 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_conv/resolve_ufcs_outer.cpp
+ * - Resolve UfcsUnknown paths in outer scope (signatures/types)
+ *
+ * RULES:
+ * - Only generics are allowed to be UfcsKnown in signatures/types (within bodies anything goes?)
+ */
+#include "main_bindings.hpp"
+#include <hir/hir.hpp>
+#include <hir/expr.hpp>
+#include <hir/visitor.hpp>
+#include <hir_typeck/common.hpp> // monomorphise_genericpath_needed
+#include <algorithm>
+
+namespace {
+ class Visitor:
+ public ::HIR::Visitor
+ {
+ const ::HIR::Crate& m_crate;
+
+ const ::HIR::GenericParams* m_params_impl = nullptr;
+ const ::HIR::GenericParams* m_params_method = nullptr;
+
+ const ::HIR::TypeRef* m_current_type = nullptr; // used because sometimes `Self` is already replaced
+ const ::HIR::Trait* m_current_trait = nullptr;
+ const ::HIR::ItemPath* m_current_trait_path = nullptr;
+
+ public:
+ Visitor(const ::HIR::Crate& crate):
+ m_crate(crate)
+ {}
+
+ void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_struct(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_enum(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_function(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_type_alias(::HIR::ItemPath p, ::HIR::TypeAlias& item) override {
+ // NOTE: Disabled, becuase generics in type aliases are never checked
+#if 0
+ auto _ = m_resolve.set_item_generics(item.m_params);
+ ::HIR::Visitor::visit_function(p, item);
+#endif
+ }
+ void visit_trait(::HIR::ItemPath p, ::HIR::Trait& trait) override {
+ m_params_impl = &trait.m_params;
+ m_current_trait = &trait;
+ m_current_trait_path = &p;
+ ::HIR::Visitor::visit_trait(p, trait);
+ m_current_trait = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_type_impl(::HIR::TypeImpl& impl) override {
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ ::HIR::Visitor::visit_type_impl(impl);
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ ::HIR::Visitor::visit_marker_impl(trait_path, impl);
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+
+ void visit_expr(::HIR::ExprPtr& expr) override
+ {
+ // No inner visiting for expressions
+ }
+
+ bool locate_trait_item_in_bounds(::HIR::Visitor::PathContext pc, const ::HIR::TypeRef& tr, const ::HIR::GenericParams& params, ::HIR::Path::Data& pd) {
+ static Span sp;
+ //const auto& name = pd.as_UfcsUnknown().item;
+ for(const auto& b : params.m_bounds)
+ {
+ TU_IFLET(::HIR::GenericBound, b, TraitBound, e,
+ DEBUG("- " << e.type << " : " << e.trait.m_path);
+ if( e.type == tr ) {
+ DEBUG(" - Match");
+ if( locate_in_trait_and_set(pc, e.trait.m_path, m_crate.get_trait_by_path(sp, e.trait.m_path.m_path), pd) ) {
+ return true;
+ }
+ }
+ );
+ // -
+ }
+ return false;
+ }
+ static ::HIR::Path::Data get_ufcs_known(::HIR::Path::Data::Data_UfcsUnknown e, ::HIR::GenericPath trait_path, const ::HIR::Trait& trait)
+ {
+ return ::HIR::Path::Data::make_UfcsKnown({ mv$(e.type), mv$(trait_path), mv$(e.item), mv$(e.params)} );
+ }
+ static bool locate_item_in_trait(::HIR::Visitor::PathContext pc, const ::HIR::Trait& trait, ::HIR::Path::Data& pd)
+ {
+ const auto& e = pd.as_UfcsUnknown();
+
+ switch(pc)
+ {
+ case ::HIR::Visitor::PathContext::VALUE:
+ if( trait.m_values.find( e.item ) != trait.m_values.end() ) {
+ return true;
+ }
+ break;
+ case ::HIR::Visitor::PathContext::TRAIT:
+ break;
+ case ::HIR::Visitor::PathContext::TYPE:
+ if( trait.m_types.find( e.item ) != trait.m_types.end() ) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+ static ::HIR::GenericPath make_generic_path(::HIR::SimplePath sp, const ::HIR::Trait& trait)
+ {
+ auto trait_path_g = ::HIR::GenericPath( mv$(sp) );
+ for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) {
+ //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef(trait.m_params.m_types[i].m_name, i) );
+ //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef() );
+ trait_path_g.m_params.m_types.push_back( trait.m_params.m_types[i].m_default.clone() );
+ }
+ return trait_path_g;
+ }
+ // Locate the item in `pd` and set `pd` to UfcsResolved if found
+ // TODO: This code may end up generating paths without the type information they should contain
+ bool locate_in_trait_and_set(::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) {
+ // TODO: Get the span from caller
+ static Span _sp;
+ const auto& sp = _sp;
+ if( locate_item_in_trait(pc, trait, pd) ) {
+ pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), trait_path.clone() /*make_generic_path(trait_path.m_path, trait)*/, trait);
+ return true;
+ }
+
+ auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& {
+ const auto& ge = ty.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ // TODO: This has to be the _exact_ same type, including future ivars.
+ return *pd.as_UfcsUnknown().type;
+ }
+ else if( (ge.binding >> 8) == 0 ) {
+ auto idx = ge.binding & 0xFF;
+ ASSERT_BUG(sp, idx < trait.m_params.m_types.size(), "");
+ if( idx < trait_path.m_params.m_types.size() )
+ return trait_path.m_params.m_types[idx];
+ // If the param is omitted, but has a default, use the default.
+ else if( trait.m_params.m_types[idx].m_default != ::HIR::TypeRef() ) {
+ const auto& def = trait.m_params.m_types[idx].m_default;
+ if( ! monomorphise_type_needed(def) )
+ return def;
+ if( def == ::HIR::TypeRef("Self", 0xFFFF) )
+ // TODO: This has to be the _exact_ same type, including future ivars.
+ return *pd.as_UfcsUnknown().type;
+ TODO(sp, "Monomorphise default arg " << def << " for trait path " << trait_path);
+ }
+ else
+ BUG(sp, "Binding out of range in " << ty << " for trait path " << trait_path);
+ }
+ else {
+ ERROR(sp, E0000, "Unexpected generic binding " << ty);
+ }
+ };
+ ::HIR::GenericPath par_trait_path_tmp;
+ auto monomorph_gp_if_needed = [&](const ::HIR::GenericPath& tpl)->const ::HIR::GenericPath& {
+ // NOTE: This doesn't monomorph if the parameter set is the same
+ if( monomorphise_genericpath_needed(tpl) && tpl.m_params != trait_path.m_params ) {
+ DEBUG("- Monomorph " << tpl);
+ return par_trait_path_tmp = monomorphise_genericpath_with(sp, tpl, monomorph_cb, false /*no infer*/);
+ }
+ else {
+ return tpl;
+ }
+ };
+
+ // Search supertraits (recursively)
+ for(const auto& pt : trait.m_parent_traits)
+ {
+ const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path);
+ DEBUG("- Check " << par_trait_path);
+ if( locate_in_trait_and_set(pc, par_trait_path, *pt.m_trait_ptr, pd) ) {
+ return true;
+ }
+ }
+ for(const auto& pt : trait.m_all_parent_traits)
+ {
+ const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path);
+ DEBUG("- Check (all) " << par_trait_path);
+ if( locate_item_in_trait(pc, *pt.m_trait_ptr, pd) ) {
+ // TODO: Don't clone if this is from the temp.
+ pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), par_trait_path.clone(), *pt.m_trait_ptr);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool resolve_UfcsUnknown_inherent(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd)
+ {
+ auto& e = pd.as_UfcsUnknown();
+ return m_crate.find_type_impls(*e.type, [&](const auto& t)->const auto& { return t; }, [&](const auto& impl) {
+ DEBUG("- matched inherent impl" << impl.m_params.fmt_args() << " " << impl.m_type);
+ // Search for item in this block
+ switch( pc )
+ {
+ case ::HIR::Visitor::PathContext::VALUE:
+ if( impl.m_methods.find(e.item) != impl.m_methods.end() ) {
+ }
+ else if( impl.m_constants.find(e.item) != impl.m_constants.end() ) {
+ }
+ else {
+ return false;
+ }
+ // Found it, just keep going (don't care about details here)
+ break;
+ case ::HIR::Visitor::PathContext::TRAIT:
+ case ::HIR::Visitor::PathContext::TYPE:
+ return false;
+ }
+
+ auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} );
+ pd = mv$(new_data);
+ DEBUG("- Resolved, replace with " << p);
+ return true;
+ });
+ }
+
+ void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override
+ {
+ static Span sp;
+
+ // Explicitly handle UfcsUnknown (doesn't call default)
+ if(auto* pe = p.m_data.opt_UfcsUnknown())
+ {
+ auto& e = *pe;
+ TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p);
+
+ this->visit_type( *e.type );
+ this->visit_path_params( e.params );
+
+ // Search for matching impls in current generic blocks
+ if( m_params_method != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_method, p.m_data) ) {
+ DEBUG("Found in item params, p = " << p);
+ return ;
+ }
+ if( m_params_impl != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_impl, p.m_data) ) {
+ DEBUG("Found in impl params, p = " << p);
+ return ;
+ }
+
+ // 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?
+ // NOTE: `Self` can already be replaced by the self type (AST resolve does this)
+ if( *e.type == ::HIR::TypeRef("Self", 0xFFFF) || (m_current_type && *e.type == *m_current_type) )
+ {
+ ::HIR::GenericPath trait_path;
+ if( m_current_trait_path->trait_path() )
+ {
+ trait_path = ::HIR::GenericPath( *m_current_trait_path->trait_path() );
+ trait_path.m_params = m_current_trait_path->trait_args()->clone();
+ }
+ else
+ {
+ 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) );
+ }
+ }
+ if( locate_in_trait_and_set(pc, trait_path, *m_current_trait, p.m_data) ) {
+ DEBUG("Found in Self, p = " << p);
+ return ;
+ }
+ DEBUG("- Item " << e.item << " not found in Self - ty=" << *e.type);
+ }
+
+ // Cases for the type:
+ // - Path:UfcsKnown - Search trait impl's ATY bounds (and our own bound set?)
+ // - Generic - Search local bound set for a suitable implemented trait
+ // - Anything else - ERROR
+ if( e.type->m_data.is_Path() && e.type->m_data.as_Path().path.m_data.is_UfcsKnown() )
+ {
+ // TODO: Search bounds on this ATY (in the trait defintiion)
+ TODO(sp, "Get " << e.item << " for " << *e.type);
+ }
+ else if( e.type->m_data.is_Generic())
+ {
+ // Local bounds have already been searched, error now?
+ TODO(sp, "Get " << e.item << " for " << *e.type);
+ }
+ else
+ {
+ ERROR(sp, E0000, "Ambigious associated type " << p); // rustc E0223
+ }
+ }
+ else
+ {
+ ::HIR::Visitor::visit_path(p, pc);
+ }
+ }
+ };
+
+}
+
+namespace {
+ template<typename T>
+ void sort_impl_group(::HIR::Crate::ImplGroup<T>& ig)
+ {
+ auto new_end = ::std::remove_if(ig.generic.begin(), ig.generic.end(), [&ig](::std::unique_ptr<T>& ty_impl) {
+ const auto& type = ty_impl->m_type; // Using field accesses in templates feels so dirty
+ const ::HIR::SimplePath* path = type.get_sort_path();
+
+ if( path )
+ {
+ ig.named[*path].push_back(mv$(ty_impl));
+ }
+ else if( type.m_data.is_Path() || type.m_data.is_Generic() )
+ {
+ return false;
+ }
+ else
+ {
+ ig.non_named.push_back(mv$(ty_impl));
+ }
+ return true;
+ });
+ ig.generic.erase(new_end, ig.generic.end());
+ }
+}
+
+void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate)
+{
+ Visitor exp { crate };
+ exp.visit_crate( crate );
+
+ // Sort impls!
+ sort_impl_group(crate.m_type_impls);
+ DEBUG("Type impl counts: " << crate.m_type_impls.named.size() << " path groups, " << crate.m_type_impls.non_named.size() << " primitive, " << crate.m_type_impls.generic.size() << " ungrouped");
+ for(auto& impl_group : crate.m_trait_impls)
+ {
+ sort_impl_group(impl_group.second);
+ }
+ for(auto& impl_group : crate.m_marker_impls)
+ {
+ sort_impl_group(impl_group.second);
+ }
+}
diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp
index 693c7745..5ce270bc 100644
--- a/src/hir_expand/annotate_value_usage.cpp
+++ b/src/hir_expand/annotate_value_usage.cpp
@@ -122,6 +122,10 @@ namespace {
void visit(::HIR::ExprNode_LoopControl& node) override
{
// NOTE: Leaf
+ if( node.m_value )
+ {
+ this->visit_node_ptr(node.m_value);
+ }
}
void visit(::HIR::ExprNode_Match& node) override
{
@@ -333,9 +337,32 @@ namespace {
}
void visit(::HIR::ExprNode_CallMethod& node) override
{
+ {
+ assert(node.m_cache.m_fcn);
+ ::HIR::ValueUsage vu = ::HIR::ValueUsage::Borrow;
+ switch(node.m_cache.m_fcn->m_receiver)
+ {
+ case ::HIR::Function::Receiver::Free:
+ BUG(node.span(), "_CallMethod resolved to free function");
+ case ::HIR::Function::Receiver::Value:
+ case ::HIR::Function::Receiver::Box:
+ case ::HIR::Function::Receiver::Custom:
+ case ::HIR::Function::Receiver::BorrowOwned:
+ vu = ::HIR::ValueUsage::Move;
+ break;
+ case ::HIR::Function::Receiver::BorrowUnique:
+ vu = ::HIR::ValueUsage::Mutate;
+ break;
+ case ::HIR::Function::Receiver::BorrowShared:
+ vu = ::HIR::ValueUsage::Borrow;
+ break;
+ //case ::HIR::Function::Receiver::PointerMut:
+ //case ::HIR::Function::Receiver::PointerConst:
+ }
+ auto _ = push_usage( vu );
+ this->visit_node_ptr(node.m_value);
+ }
auto _ = push_usage( ::HIR::ValueUsage::Move );
-
- this->visit_node_ptr(node.m_value);
for( auto& val : node.m_args )
this->visit_node_ptr(val);
}
@@ -356,13 +383,15 @@ namespace {
void visit(::HIR::ExprNode_StructLiteral& node) override
{
const auto& sp = node.span();
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
if( node.m_base_value ) {
bool is_moved = false;
const auto& tpb = node.m_base_value->m_res_type.m_data.as_Path().binding;
const ::HIR::Struct* str;
if( tpb.is_Enum() ) {
const auto& enm = *tpb.as_Enum();
- auto idx = enm.find_variant(node.m_path.m_path.m_components.back());
+ auto idx = enm.find_variant(ty_path.m_path.m_components.back());
ASSERT_BUG(sp, idx != SIZE_MAX, "");
const auto& var_ty = enm.m_data.as_Data()[idx].type;
str = var_ty.m_data.as_Path().binding.as_Struct();
@@ -379,7 +408,7 @@ namespace {
provided_mask[idx] = true;
}
- const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &node.m_path.m_params, nullptr);
+ const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &ty_path.m_params, nullptr);
for( unsigned int i = 0; i < fields.size(); i ++ ) {
if( ! provided_mask[i] ) {
const auto& ty_o = fields[i].second.ent;
@@ -452,11 +481,19 @@ namespace {
throw "";
}
- ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const
+ ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& outer_ty) const
{
if( pat.m_binding.is_valid() ) {
- return get_usage_for_pattern_binding(sp, pat.m_binding, ty);
+ return get_usage_for_pattern_binding(sp, pat.m_binding, outer_ty);
+ }
+
+ // Implicit derefs
+ const ::HIR::TypeRef* typ = &outer_ty;
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ typ = &*typ->m_data.as_Borrow().inner;
}
+ const ::HIR::TypeRef& ty = *typ;
TU_MATCHA( (pat.m_data), (pe),
(Any,
@@ -510,6 +547,12 @@ namespace {
),
(Struct,
const auto& str = *pe.binding;
+ if( pe.is_wildcard() )
+ return ::HIR::ValueUsage::Borrow;
+ if( pe.sub_patterns.empty() && (TU_TEST1(str.m_data, Tuple, .empty()) || str.m_data.is_Unit()) ) {
+ return ::HIR::ValueUsage::Borrow;
+ }
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-brace struct");
const auto& flds = str.m_data.as_Named();
auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr);
@@ -552,10 +595,10 @@ namespace {
),
(EnumStruct,
const auto& enm = *pe.binding_ptr;
- ASSERT_BUG(sp, enm.m_data.is_Data(), "");
+ ASSERT_BUG(sp, enm.m_data.is_Data(), "EnumStruct pattern on non-data enum");
const auto& var = enm.m_data.as_Data().at(pe.binding_idx);
const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
- ASSERT_BUG(sp, str.m_data.is_Named(), "");
+ ASSERT_BUG(sp, str.m_data.is_Named(), "EnumStruct pattern on non-struct variant - " << pe.path);
const auto& flds = str.m_data.as_Named();
auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr);
diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp
index 51b2c638..c53396a0 100644
--- a/src/hir_expand/closures.cpp
+++ b/src/hir_expand/closures.cpp
@@ -9,6 +9,7 @@
#include <hir/expr.hpp>
#include <hir_typeck/static.hpp>
#include <algorithm>
+#include <hir/expr_state.hpp>
#include "main_bindings.hpp"
namespace {
@@ -18,7 +19,7 @@ namespace {
namespace {
- typedef ::std::function< ::HIR::SimplePath(::HIR::Struct )> new_type_cb_t;
+ typedef ::std::function< ::std::pair<::HIR::SimplePath, const ::HIR::Struct*>(const char* suffix, ::HIR::Struct )> new_type_cb_t;
typedef ::std::vector< ::std::pair< ::HIR::ExprNode_Closure::Class, ::HIR::TraitImpl> > out_impls_t;
template<typename K, typename V>
@@ -45,6 +46,50 @@ namespace {
return rv;
}
+ void push_new_impls(const Span& sp, ::HIR::Crate& crate, out_impls_t new_trait_impls)
+ {
+ for(auto& impl : new_trait_impls)
+ {
+ ::HIR::Crate::ImplGroup<::HIR::TraitImpl>::list_t* trait_impl_list;
+ switch(impl.first)
+ {
+ case ::HIR::ExprNode_Closure::Class::Once:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn_once")].get_list_for_type_mut(impl.second.m_type);
+ if(0)
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn_mut" )].get_list_for_type_mut(impl.second.m_type);
+ if(0)
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn" )].get_list_for_type_mut(impl.second.m_type);
+ trait_impl_list->push_back( box$(impl.second) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::NoCapture: {
+ assert(impl.second.m_methods.size() == 1);
+ assert(impl.second.m_types.empty());
+ assert(impl.second.m_constants.empty());
+ // NOTE: This should always have a name
+ const auto& path = impl.second.m_type.m_data.as_Path().path.m_data.as_Generic().m_path;
+ DEBUG("Adding type impl " << path);
+ auto* list_it = &crate.m_type_impls.named[path];
+ list_it->push_back(box$(::HIR::TypeImpl {
+ mv$(impl.second.m_params),
+ mv$(impl.second.m_type),
+ make_map1(
+ impl.second.m_methods.begin()->first,
+ ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { ::HIR::Publicity::new_global(), false, mv$(impl.second.m_methods.begin()->second.data) }
+ ),
+ {},
+ mv$(impl.second.m_src_module)
+ }));
+ } break;
+ case ::HIR::ExprNode_Closure::Class::Unknown:
+ BUG(Span(), "Encountered Unkown closure type in new impls");
+ break;
+ }
+ }
+ new_trait_impls.resize(0);
+ }
+
/// Mutate the contents of a closure to update captures, variables, and types
class ExprVisitor_Mutate:
public ::HIR::ExprVisitorDef
@@ -106,7 +151,7 @@ namespace {
assert( node_ptr );
auto& node = *node_ptr;
const char* node_ty = typeid(node).name();
- TRACE_FUNCTION_FR(&node << " " << node_ty << " : " << node.m_res_type, node_ty);
+ TRACE_FUNCTION_FR("[_Mutate] " << &node << " " << node_ty << " : " << node.m_res_type, node_ty);
node.visit(*this);
if( m_replacement ) {
@@ -134,7 +179,9 @@ namespace {
auto binding_it = ::std::find(m_local_vars.begin(), m_local_vars.end(), node.m_slot);
if( binding_it != m_local_vars.end() ) {
// NOTE: Offset of 1 is for `self` (`args` is destructured)
- node.m_slot = 1 + binding_it - m_local_vars.begin();
+ auto new_slot = 1 + binding_it - m_local_vars.begin();
+ DEBUG("_Variable: #" << node.m_slot << " -> #" << new_slot);
+ node.m_slot = new_slot;
return ;
}
}
@@ -146,7 +193,7 @@ namespace {
{
m_replacement = NEWNODE(node.m_res_type.clone(), Field, node.span(),
get_self(node.span()),
- FMT(binding_it - m_captures.begin())
+ RcString::new_interned(FMT(binding_it - m_captures.begin()))
);
if( binding_it->second != ::HIR::ValueUsage::Move ) {
auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared);
@@ -156,6 +203,7 @@ namespace {
m_replacement = NEWNODE(node.m_res_type.clone(), Deref, node.span(), mv$(m_replacement));
}
m_replacement->m_usage = node.m_usage;
+ DEBUG("_Variable: #" << node.m_slot << " -> capture");
return ;
}
}
@@ -194,22 +242,38 @@ namespace {
public ::HIR::ExprVisitorDef
{
const ::HIR::Crate& m_crate;
+ StaticTraitResolve m_resolve;
t_cb_generic m_monomorph_cb;
+ bool m_run_eat;
public:
- ExprVisitor_Fixup(const ::HIR::Crate& crate, t_cb_generic monomorph_cb):
+ ExprVisitor_Fixup(const ::HIR::Crate& crate, const ::HIR::GenericParams* params, t_cb_generic monomorph_cb):
m_crate(crate),
- m_monomorph_cb( mv$(monomorph_cb) )
+ m_resolve(crate),
+ m_monomorph_cb( mv$(monomorph_cb) ),
+ m_run_eat(false)
{
+ if( params ) {
+ m_resolve.set_impl_generics_raw(*params);
+ m_run_eat = true;
+ }
}
- static void fix_type(const ::HIR::Crate& crate, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) {
+ static void fix_type(const ::HIR::Crate& crate, const Span& sp, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) {
TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Closure, e,
DEBUG("Closure: " << e.node->m_obj_path_base);
- auto path = monomorphise_genericpath_with(Span(), e.node->m_obj_path_base, monomorph_cb, false);
- const auto& str = crate.get_struct_by_path( Span(), path.m_path );
+ auto path = monomorphise_genericpath_with(sp, e.node->m_obj_path_base, monomorph_cb, false);
+ const auto& str = *e.node->m_obj_ptr;
DEBUG(ty << " -> " << path);
ty = ::HIR::TypeRef::new_path( mv$(path), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) );
)
+
+ if( auto* e = ty.m_data.opt_Path() )
+ {
+ if( e->binding.is_Unbound() && e->path.m_data.is_UfcsKnown() )
+ {
+ e->binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ }
}
void visit_root(::HIR::ExprPtr& root)
@@ -233,6 +297,42 @@ namespace {
visit_type(node->m_res_type);
}
+ void visit(::HIR::ExprNode_Cast& node) override
+ {
+ const Span& sp = node.span();
+ // Handle casts from closures to function pointers
+ if( node.m_value->m_res_type.m_data.is_Closure() )
+ {
+ const auto& src_te = node.m_value->m_res_type.m_data.as_Closure();
+ ASSERT_BUG(sp, node.m_res_type.m_data.is_Function(), "Cannot convert closure to non-fn type");
+ //const auto& dte = node.m_res_type.m_data.as_Function();
+ if( src_te.node->m_class != ::HIR::ExprNode_Closure::Class::NoCapture )
+ {
+ ERROR(sp, E0000, "Cannot cast a closure with captures to a fn() type");
+ }
+
+ ::HIR::FunctionType fcn_ty_inner { /*is_unsafe=*/false, ABI_RUST, box$(src_te.node->m_return.clone()), {} };
+ ::std::vector<::HIR::TypeRef> arg_types;
+ fcn_ty_inner.m_arg_types.reserve(src_te.node->m_args.size());
+ arg_types.reserve(src_te.node->m_args.size());
+ for(const auto& arg : src_te.node->m_args)
+ {
+ fcn_ty_inner.m_arg_types.push_back( arg.second.clone() );
+ arg_types.push_back(arg.second.clone());
+ }
+ auto trait_params = ::HIR::PathParams( ::HIR::TypeRef(mv$(arg_types)) );
+ auto res_ty = ::HIR::TypeRef(mv$(fcn_ty_inner));
+
+ const auto& str = *src_te.node->m_obj_ptr;
+ auto closure_type = ::HIR::TypeRef::new_path( src_te.node->m_obj_path.clone(), &str );
+ auto fn_path = ::HIR::Path(mv$(closure_type), "call_free");
+ fn_path.m_data.as_UfcsInherent().impl_params = src_te.node->m_obj_path.m_params.clone();
+
+ node.m_value = NEWNODE(mv$(res_ty), PathValue, sp, mv$(fn_path), ::HIR::ExprNode_PathValue::FUNCTION);
+ }
+ ::HIR::ExprVisitorDef::visit(node);
+ }
+
void visit(::HIR::ExprNode_CallValue& node) override
{
TU_IFLET( ::HIR::TypeRef::Data, node.m_value->m_res_type.m_data, Closure, e,
@@ -258,8 +358,15 @@ namespace {
void visit_type(::HIR::TypeRef& ty) override
{
- fix_type(m_crate, m_monomorph_cb, ty);
+ bool run_eat = m_run_eat;
+ m_run_eat = false;
+ fix_type(m_crate, Span(), m_monomorph_cb, ty);
::HIR::ExprVisitorDef::visit_type(ty);
+ if( run_eat ) {
+ // TODO: Instead of running EAT, just mark any Unbound UfcsKnown types as Opaque
+ //m_resolve.expand_associated_types(Span(), ty);
+ m_run_eat = true;
+ }
}
};
@@ -280,6 +387,37 @@ namespace {
code.m_bindings[0] = self_ty.clone();
}
}
+ static ::HIR::TraitImpl make_fnfree(
+ ::HIR::GenericParams params,
+ ::HIR::TypeRef closure_type,
+ ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args,
+ ::HIR::TypeRef ret_ty,
+ ::HIR::ExprPtr code
+ )
+ {
+ // NOTE: Fixup isn't needed, there's no self
+ //fix_fn_params(code, closure_type, args_argent.second);
+ assert(code.m_bindings.size() > 0);
+ code.m_bindings[0] = ::HIR::TypeRef::new_unit();
+ return ::HIR::TraitImpl {
+ mv$(params), {}, mv$(closure_type),
+ make_map1(
+ RcString::new_interned("call_free"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ false, ::HIR::Linkage {},
+ ::HIR::Function::Receiver::Free,
+ ABI_RUST, false, false,
+ {},
+ mv$(args), false,
+ ret_ty.clone(),
+ mv$(code)
+ } }
+ ),
+ {},
+ {},
+ {},
+ ::HIR::SimplePath()
+ };
+ }
static ::HIR::TraitImpl make_fnonce(
::HIR::GenericParams params,
::HIR::PathParams trait_params,
@@ -294,7 +432,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::Value,
ABI_RUST, false, false,
@@ -313,7 +451,7 @@ namespace {
{},
{},
make_map1(
- ::std::string("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) }
+ RcString::new_interned("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) }
),
::HIR::SimplePath()
};
@@ -332,7 +470,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::BorrowUnique,
ABI_RUST, false, false,
@@ -368,7 +506,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::BorrowShared,
ABI_RUST, false, false,
@@ -419,17 +557,19 @@ namespace {
// Outputs
out_impls_t& m_out_impls;
+ const char* m_new_type_suffix;
const new_type_cb_t& m_new_type;
/// Stack of active closures
::std::vector<ClosureScope> m_closure_stack;
public:
- ExprVisitor_Extract(const StaticTraitResolve& resolve, const ::HIR::TypeRef* self_type, ::std::vector< ::HIR::TypeRef>& var_types, out_impls_t& out_impls, const new_type_cb_t& new_type):
+ ExprVisitor_Extract(const StaticTraitResolve& resolve, const ::HIR::TypeRef* self_type, ::std::vector< ::HIR::TypeRef>& var_types, out_impls_t& out_impls, const char* nt_suffix, const new_type_cb_t& new_type):
m_resolve(resolve),
m_self_type(self_type),
m_variable_types(var_types),
m_out_impls( out_impls ),
+ m_new_type_suffix(nt_suffix),
m_new_type( new_type )
{
}
@@ -445,6 +585,8 @@ namespace {
TRACE_FUNCTION_F("Extract closure - " << node.m_res_type);
+ ASSERT_BUG(sp, node.m_obj_path == ::HIR::GenericPath(), "Closure path already set? " << node.m_obj_path);
+
// --- Determine borrow set ---
m_closure_stack.push_back( ClosureScope(node) );
@@ -507,6 +649,7 @@ namespace {
params_placeholders.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) );
impl_path_params.m_types.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) );
}
+ DEBUG("params_placeholders = " << params_placeholders << ", ofs_item = " << ofs_item << ", ofs_impl = " << ofs_impl);
auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& {
const auto& ge = ty.m_data.as_Generic();
@@ -593,6 +736,7 @@ namespace {
::std::vector< ::HIR::ExprNodeP> capture_nodes;
capture_types.reserve( ent.captured_vars.size() );
capture_nodes.reserve( ent.captured_vars.size() );
+ node.m_is_copy = true;
for(const auto binding : ent.captured_vars)
{
const auto binding_idx = binding.first;
@@ -627,20 +771,34 @@ namespace {
}
// - Fix type to replace closure types with known paths
- ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb };
+ ExprVisitor_Fixup fixup { m_resolve.m_crate, &params, monomorph_cb };
fixup.visit_type(ty_mono);
- capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { false, mv$(ty_mono) } );
+ if( !m_resolve.type_is_copy(sp, ty_mono) )
+ {
+ node.m_is_copy = false;
+ }
+ capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_none(), mv$(ty_mono) } );
}
- auto closure_struct_path = m_new_type(
- ::HIR::Struct {
- params.clone(),
- ::HIR::Struct::Repr::Rust,
- ::HIR::Struct::Data::make_Tuple(mv$(capture_types))
- }
- );
- const auto& closure_struct_ref = m_resolve.m_crate.get_struct_by_path(sp, closure_struct_path);
+
+ // --- ---
+ if( node.m_is_copy )
+ {
+ DEBUG("Copy closure");
+ }
+
+ auto str = ::HIR::Struct {
+ params.clone(),
+ ::HIR::Struct::Repr::Rust,
+ ::HIR::Struct::Data::make_Tuple(mv$(capture_types))
+ };
+ str.m_markings.is_copy = node.m_is_copy;
+ ::HIR::SimplePath closure_struct_path;
+ const ::HIR::Struct* closure_struct_ptr;
+ ::std::tie(closure_struct_path, closure_struct_ptr) = m_new_type(m_new_type_suffix, mv$(str));
+ const auto& closure_struct_ref = *closure_struct_ptr;
// Mark the object pathname in the closure.
+ node.m_obj_ptr = &closure_struct_ref;
node.m_obj_path = ::HIR::GenericPath( closure_struct_path, mv$(constructor_path_params) );
node.m_obj_path_base = node.m_obj_path.clone();
node.m_captures = mv$(capture_nodes);
@@ -669,7 +827,7 @@ namespace {
{
DEBUG("-- Fixing types in body code");
- ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb };
+ ExprVisitor_Fixup fixup { m_resolve.m_crate, &params, monomorph_cb };
fixup.visit_root( body_code );
DEBUG("-- Fixing types in signature");
@@ -678,6 +836,19 @@ namespace {
// TODO: Replace erased types too
}
+ if( node.m_is_copy )
+ {
+ auto& v = const_cast<::HIR::Crate&>(m_resolve.m_crate).m_trait_impls[m_resolve.m_crate.get_lang_item_path(sp, "copy")].get_list_for_type_mut(closure_type);
+ v.push_back(box$(::HIR::TraitImpl {
+ params.clone(), {}, closure_type.clone(),
+ {},
+ {},
+ {},
+ {},
+ /*source module*/::HIR::SimplePath(m_resolve.m_crate.m_crate_name, {})
+ }));
+ }
+
// ---
// 3. Create trait impls
// ---
@@ -687,7 +858,83 @@ namespace {
{
case ::HIR::ExprNode_Closure::Class::Unknown:
node.m_class = ::HIR::ExprNode_Closure::Class::NoCapture;
- case ::HIR::ExprNode_Closure::Class::NoCapture:
+ case ::HIR::ExprNode_Closure::Class::NoCapture: {
+
+ struct H2 {
+ static ::std::pair<::HIR::ExprNode_Closure::Class, HIR::TraitImpl> make_dispatch(
+ const Span& sp,
+ ::HIR::ExprNode_Closure::Class c,
+ ::HIR::GenericParams params,
+ ::HIR::PathParams trait_params,
+ const ::HIR::TypeRef& closure_type,
+ const ::HIR::TypeRef& args_ty,
+ const ::HIR::TypeRef& ret_type
+ )
+ {
+ const auto& args_tup_inner = args_ty.m_data.as_Tuple();
+ // 1. Create a list of `arg.0, arg.1, arg.2, ...` for the dispatch methods
+ ::std::vector<HIR::ExprNodeP> dispatch_args;
+ ::std::vector<HIR::TypeRef> dispatch_node_args_cache;
+ dispatch_args.reserve( args_tup_inner.size() );
+ dispatch_node_args_cache.reserve( args_tup_inner.size()+1 );
+ for(size_t i = 0; i < args_tup_inner.size(); i ++)
+ {
+ const auto& ty = args_tup_inner[i];
+ dispatch_args.push_back( NEWNODE(ty.clone(), Field, sp, NEWNODE(args_ty.clone(), Variable, sp, RcString::new_interned("arg"), 1), RcString::new_interned(FMT(i))) );
+ dispatch_node_args_cache.push_back( ty.clone() );
+ }
+ dispatch_node_args_cache.push_back( ret_type.clone() );
+ auto path = ::HIR::Path(closure_type.clone(), RcString::new_interned("call_free"));
+ path.m_data.as_UfcsInherent().impl_params = closure_type.m_data.as_Path().path.m_data.as_Generic().m_params.clone();
+ HIR::ExprNodeP dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp,
+ mv$(path),
+ mv$(dispatch_args)
+ );
+ dynamic_cast<::HIR::ExprNode_CallPath&>(*dispatch_node).m_cache.m_arg_types = mv$(dispatch_node_args_cache);
+
+ auto args_arg = ::std::make_pair(
+ ::HIR::Pattern { {false, ::HIR::PatternBinding::Type::Move, RcString::new_interned("args"), 1}, {} },
+ args_ty.clone()
+ );
+ HIR::TraitImpl fcn;
+ switch(c)
+ {
+ case ::HIR::ExprNode_Closure::Class::Once:
+ fcn = H::make_fnonce( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ fcn = H::make_fnmut( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ fcn = H::make_fn( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ default:
+ throw "";
+ }
+ return ::std::make_pair(c, mv$(fcn));
+ }
+ };
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Once , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) );
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Mut , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) );
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Shared, params.clone(), mv$(trait_params) , closure_type, args_ty, ret_type) );
+
+ // 2. Split args_pat/args_ty into separate arguments
+ ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args_split;
+ args_split.reserve( node.m_args.size() );
+ for(size_t i = 0; i < node.m_args.size(); i ++)
+ {
+ args_split.push_back(::std::make_pair(
+ mv$( args_pat.m_data.as_Tuple().sub_patterns[i] ),
+ mv$( args_ty.m_data.as_Tuple()[i] )
+ ));
+ }
+ // - Create fn_free free method
+ m_out_impls.push_back(::std::make_pair(
+ ::HIR::ExprNode_Closure::Class::NoCapture,
+ H::make_fnfree( mv$(params), mv$(closure_type), mv$(args_split), mv$(ret_type), mv$(body_code) )
+ ));
+
+ } break;
case ::HIR::ExprNode_Closure::Class::Shared: {
const auto& lang_Fn = m_resolve.m_crate.get_lang_item_path(node.span(), "fn");
const auto method_self_ty = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, closure_type.clone() );
@@ -695,9 +942,9 @@ namespace {
// - FnOnce
{
auto dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp,
- ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), "call"),
+ ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), RcString::new_interned("call")),
make_vec2(
- NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, "self", 0)),
+ NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, RcString::new_interned("self"), 0)),
NEWNODE(args_ty.clone(), Variable, sp, "arg", 1)
)
);
@@ -787,6 +1034,7 @@ namespace {
}
void visit(::HIR::ExprNode_Variable& node) override
{
+ DEBUG("_Variable: #" << node.m_slot << " '" << node.m_name << "' " << node.m_usage);
if( !m_closure_stack.empty() )
{
mark_used_variable(node.span(), node.m_slot, node.m_usage);
@@ -1012,26 +1260,19 @@ namespace {
unsigned int closure_count = 0;
::HIR::SimplePath root_mod_path(crate.m_crate_name,{});
m_cur_mod_path = &root_mod_path;
- m_new_type = [&](auto s)->auto {
- auto name = FMT("closure_I_" << closure_count);
+ m_new_type = [&](const char* suffix, auto s)->auto {
+ auto name = RcString::new_interned(FMT("closure#I_" << closure_count));
closure_count += 1;
- auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) } ));
+ auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } ));
+ auto* ret_ptr = &boxed->ent.as_Struct();
crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
- return ::HIR::SimplePath(crate.m_crate_name, {}) + name;
+ return ::std::make_pair( ::HIR::SimplePath(crate.m_crate_name, {}) + name, ret_ptr );
};
::HIR::Visitor::visit_crate(crate);
- for(auto& impl : m_new_trait_impls)
- {
- const auto& trait =
- impl.first == ::HIR::ExprNode_Closure::Class::Once ? crate.get_lang_item_path(sp, "fn_once")
- : impl.first == ::HIR::ExprNode_Closure::Class::Mut ? crate.get_lang_item_path(sp, "fn_mut")
- : /*impl.first == ::HIR::ExprNode_Closure::Class::Shared ?*/ crate.get_lang_item_path(sp, "fn")
- ;
- crate.m_trait_impls.insert( ::std::make_pair(trait.clone(), mv$(impl.second)) );
- }
- m_new_trait_impls.resize(0);
+ push_new_impls(sp, crate, mv$(m_new_trait_impls));
+ m_new_trait_impls.clear();
}
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
@@ -1040,20 +1281,29 @@ namespace {
auto path = p.get_simple_path();
m_cur_mod_path = &path;
+ ::std::vector< ::std::pair<RcString, std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >> new_types;
+
unsigned int closure_count = 0;
auto saved_nt = mv$(m_new_type);
- m_new_type = [&](auto s)->auto {
- auto name = FMT("closure_" << closure_count);
+ m_new_type = [&](const char* suffix, auto s)->auto {
+ // TODO: Use a function on `mod` that adds a closure and makes the indexes be per suffix
+ auto name = RcString( FMT("closure#" << suffix << (suffix[0] ? "_" : "") << closure_count) );
closure_count += 1;
- auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) }) );
- mod.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
- return (p + name).get_simple_path();
+ auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) }) );
+ auto* ret_ptr = &boxed->ent.as_Struct();
+ new_types.push_back( ::std::make_pair(name, mv$(boxed)) );
+ return ::std::make_pair( (p + name).get_simple_path(), ret_ptr );
};
::HIR::Visitor::visit_module(p, mod);
m_cur_mod_path = saved;
m_new_type = mv$(saved_nt);
+
+ for(auto& e : new_types)
+ {
+ mod.m_mod_items.insert( mv$(e) );
+ }
}
// NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure
@@ -1088,12 +1338,12 @@ namespace {
DEBUG("Function code " << p);
{
- ExprVisitor_Extract ev(m_resolve, m_self_type, item.m_code.m_bindings, m_new_trait_impls, m_new_type);
+ ExprVisitor_Extract ev(m_resolve, m_self_type, item.m_code.m_bindings, m_new_trait_impls, p.name, m_new_type);
ev.visit_root( *item.m_code );
}
{
- ExprVisitor_Fixup fixup(m_resolve.m_crate, [](const auto& x)->const auto&{ return x; });
+ ExprVisitor_Fixup fixup(m_resolve.m_crate, nullptr, [](const auto& x)->const auto&{ return x; });
fixup.visit_root( item.m_code );
}
}
@@ -1152,6 +1402,8 @@ namespace {
m_self_type = &impl.m_type;
auto _ = this->m_resolve.set_impl_generics(impl.m_params);
+ // TODO: Re-create m_new_type to store in the source module
+
::HIR::Visitor::visit_type_impl(impl);
m_self_type = nullptr;
@@ -1169,9 +1421,50 @@ namespace {
};
}
-void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp)
+void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate_ro, ::HIR::ExprPtr& exp)
{
- // TODO:
+ Span sp;
+ auto& crate = const_cast<::HIR::Crate&>(crate_ro);
+ TRACE_FUNCTION;
+
+ StaticTraitResolve resolve { crate };
+ assert(exp);
+ if(exp.m_state->m_impl_generics) resolve.set_impl_generics(*exp.m_state->m_impl_generics);
+ if(exp.m_state->m_item_generics) resolve.set_item_generics(*exp.m_state->m_item_generics);
+
+ const ::HIR::TypeRef* self_type = nullptr; // TODO: Need to be able to get this?
+
+ static int closure_count = 0;
+ out_impls_t new_trait_impls;
+ new_type_cb_t new_type_cb = [&](const char* suffix, auto s)->auto {
+ auto name = RcString::new_interned(FMT("closure#C_" << closure_count));
+ closure_count += 1;
+ auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } ));
+ auto* ret_ptr = &boxed->ent.as_Struct();
+ crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
+ return ::std::make_pair( ::HIR::SimplePath(crate.m_crate_name, {}) + name, ret_ptr );
+ };
+
+ {
+ ExprVisitor_Extract ev(resolve, self_type, exp.m_bindings, new_trait_impls, "", new_type_cb);
+ ev.visit_root( *exp );
+ }
+
+ {
+ ExprVisitor_Fixup fixup(crate, nullptr, [](const auto& x)->const auto&{ return x; });
+ fixup.visit_root( exp );
+ }
+
+ for(auto& impl : new_trait_impls)
+ {
+ for( auto& m : impl.second.m_methods )
+ {
+ m.second.data.m_code.m_state = ::HIR::ExprStatePtr(*exp.m_state);
+ m.second.data.m_code.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
+ }
+ impl.second.m_src_module = exp.m_state->m_mod_path;
+ }
+ push_new_impls(sp, crate, mv$(new_trait_impls));
}
void HIR_Expand_Closures(::HIR::Crate& crate)
diff --git a/src/hir_expand/reborrow.cpp b/src/hir_expand/reborrow.cpp
index cb466f6f..ecf37c64 100644
--- a/src/hir_expand/reborrow.cpp
+++ b/src/hir_expand/reborrow.cpp
@@ -87,6 +87,10 @@ namespace {
return node_ptr;
}
+ void visit(::HIR::ExprNode_Cast& node) override {
+ ::HIR::ExprVisitorDef::visit(node);
+ node.m_value = do_reborrow(mv$(node.m_value));
+ }
void visit(::HIR::ExprNode_Emplace& node) override {
::HIR::ExprVisitorDef::visit(node);
node.m_value = do_reborrow(mv$(node.m_value));
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_expand/vtable.cpp b/src/hir_expand/vtable.cpp
index 79e163ac..d2afff5d 100644
--- a/src/hir_expand/vtable.cpp
+++ b/src/hir_expand/vtable.cpp
@@ -17,7 +17,7 @@ namespace {
{
const ::HIR::Crate& m_crate;
//StaticTraitResolve m_resolve;
- ::std::function<::HIR::SimplePath(bool, ::std::string, ::HIR::Struct)> m_new_type;
+ ::std::function<::HIR::SimplePath(bool, RcString, ::HIR::Struct)> m_new_type;
::HIR::SimplePath m_lang_Sized;
public:
OuterVisitor(const ::HIR::Crate& crate):
@@ -32,7 +32,7 @@ namespace {
::std::vector< decltype(mod.m_mod_items)::value_type> new_types;
m_new_type = [&](bool pub, auto name, auto s)->auto {
- auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { pub, ::HIR::TypeItem( mv$(s) ) }) );
+ auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { (pub ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none()), ::HIR::TypeItem( mv$(s) ) }) );
auto ret = (p + name).get_simple_path();
new_types.push_back( ::std::make_pair( mv$(name), mv$(boxed)) );
return ret;
@@ -72,7 +72,7 @@ namespace {
//TODO(Span(), "Handle conflicting associated types - '" << ty.first << "'");
}
else {
- params.m_types.push_back( ::HIR::TypeParamDef { "a#"+ty.first, {}, ty.second.is_sized } );
+ params.m_types.push_back( ::HIR::TypeParamDef { RcString::new_interned(FMT("a#" << ty.first)), {}, ty.second.is_sized } );
}
i ++;
}
@@ -98,14 +98,14 @@ namespace {
auto clone_cb = [&](const auto& t, auto& o) {
if(t.m_data.is_Path() && t.m_data.as_Path().path.m_data.is_UfcsKnown()) {
const auto& pe = t.m_data.as_Path().path.m_data.as_UfcsKnown();
- bool is_self = (*pe.type == ::HIR::TypeRef("Self", 0xFFFF));
+ bool is_self = (*pe.type == ::HIR::TypeRef(RcString::new_interned("Self"), 0xFFFF));
auto it = trait_ptr->m_type_indexes.find(pe.item);
bool has_item = (it != trait_ptr->m_type_indexes.end());
// TODO: Check the trait against m_type_indexes
if( is_self /*&& pe.trait == trait_path*/ && has_item ) {
DEBUG("[clone_cb] t=" << t << " -> " << it->second);
// Replace with a new type param, need to know the index of it
- o = ::HIR::TypeRef("a#"+pe.item, it->second);
+ o = ::HIR::TypeRef( RcString::new_interned(FMT("a#" << pe.item)), it->second);
return true;
}
else {
@@ -173,7 +173,7 @@ namespace {
DEBUG("- '" << vi.first << "' is @" << fields.size());
fields.push_back( ::std::make_pair(
vi.first,
- ::HIR::VisEnt< ::HIR::TypeRef> { true, mv$(fcn_type) }
+ ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_global(), mv$(fcn_type) }
) );
),
(Static,
@@ -204,11 +204,11 @@ namespace {
ft.m_abi = ABI_RUST;
ft.m_rettype.reset( new ::HIR::TypeRef(::HIR::TypeRef::new_unit()) );
ft.m_arg_types.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ::HIR::TypeRef::new_unit()) );
- vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::TypeRef(mv$(ft)) } ));
+ vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::TypeRef(mv$(ft)) } ));
// - Size of data
- vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } ));
// - Alignment of data
- vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } ));
// - Add methods
if( ! vtc.add_ents_from_trait(tr, trait_path) )
{
@@ -231,12 +231,12 @@ namespace {
}
}
// TODO: Would like to have access to the publicity marker
- auto item_path = m_new_type(true, FMT(p.get_name() << "#vtable"), ::HIR::Struct {
- mv$(args),
- ::HIR::Struct::Repr::Rust,
- ::HIR::Struct::Data(mv$(fields)),
- {}
- });
+ auto item_path = m_new_type(
+ true,
+ RcString::new_interned(FMT(p.get_name() << "#vtable")),
+ ::HIR::Struct(mv$(args), ::HIR::Struct::Repr::Rust, ::HIR::Struct::Data(mv$(fields)))
+ );
+ tr.m_vtable_path = item_path;
DEBUG("Vtable structure created - " << item_path);
::HIR::GenericPath path( mv$(item_path), mv$(params) );
diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp
index e78ed21b..1bb21f99 100644
--- a/src/hir_typeck/common.cpp
+++ b/src/hir_typeck/common.cpp
@@ -113,6 +113,10 @@ bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback)
)
return false;
}
+bool visit_path_tys_with(const ::HIR::Path& path, t_cb_visit_ty callback)
+{
+ return visit_ty_with__path(path, callback);
+}
bool monomorphise_pathparams_needed(const ::HIR::PathParams& tpl)
{
@@ -140,7 +144,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
}
-::HIR::PathParams clone_ty_with__path_params(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) {
+::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) {
::HIR::PathParams rv;
rv.m_types.reserve( tpl.m_types.size() );
for( const auto& ty : tpl.m_types)
@@ -148,7 +152,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
return rv;
}
::HIR::GenericPath clone_ty_with__generic_path(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_clone_ty callback) {
- return ::HIR::GenericPath( tpl.m_path, clone_ty_with__path_params(sp, tpl.m_params, callback) );
+ return ::HIR::GenericPath( tpl.m_path, clone_path_params_with(sp, tpl.m_params, callback) );
}
::HIR::TraitPath clone_ty_with__trait_path(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_clone_ty callback) {
::HIR::TraitPath rv {
@@ -177,22 +181,22 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
box$( clone_ty_with(sp, *e2.type, callback) ),
clone_ty_with__generic_path(sp, e2.trait, callback),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback)
+ clone_path_params_with(sp, e2.params, callback)
});
),
(UfcsUnknown,
return ::HIR::Path::Data::make_UfcsUnknown({
box$( clone_ty_with(sp, *e2.type, callback) ),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback)
+ clone_path_params_with(sp, e2.params, callback)
});
),
(UfcsInherent,
return ::HIR::Path::Data::make_UfcsInherent({
box$( clone_ty_with(sp, *e2.type, callback) ),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback),
- clone_ty_with__path_params(sp, e2.impl_params, callback)
+ clone_path_params_with(sp, e2.params, callback),
+ clone_path_params_with(sp, e2.impl_params, callback)
});
)
)
@@ -203,7 +207,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
::HIR::TypeRef rv;
if( callback(tpl, rv) ) {
- DEBUG(tpl << " => " << rv);
+ //DEBUG(tpl << " => " << rv);
return rv;
}
@@ -222,8 +226,9 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
clone_ty_with__path(sp, e.path, callback),
e.binding.clone()
} );
- // If the input binding was Opaque, clear it back to Unbound
- if( e.binding.is_Opaque() ) {
+ // If the input binding was Opaque, AND the type changed, clear it back to Unbound
+ if( e.binding.is_Opaque() /*&& rv != tpl*/ ) {
+ // NOTE: The replacement can be Self=Self, which should trigger a binding clear.
rv.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding();
}
),
@@ -319,7 +324,7 @@ namespace {
::HIR::PathParams monomorphise_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer)
{
- return clone_ty_with__path_params(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer));
+ return clone_path_params_with(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer));
}
::HIR::GenericPath monomorphise_genericpath_with(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer)
{
diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp
index 09a5d9b2..9d662100 100644
--- a/src/hir_typeck/common.hpp
+++ b/src/hir_typeck/common.hpp
@@ -29,14 +29,33 @@ extern ::HIR::Path monomorphise_path_with(const Span& sp, const ::HIR::Path& tpl
extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true);
extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl);
+// Wrappers to only monomorphise if required
+static inline const ::HIR::TypeRef& monomorphise_type_with_opt(const Span& sp, ::HIR::TypeRef& tmp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::Path& monomorphise_path_with_opt(const Span& sp, ::HIR::Path& tmp, const ::HIR::Path& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_path_needed(tpl) ? tmp = monomorphise_path_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::GenericPath& monomorphise_genericpath_with_opt(const Span& sp, ::HIR::GenericPath& tmp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_genericpath_needed(tpl) ? tmp = monomorphise_genericpath_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::TraitPath& monomorphise_traitpath_with_opt(const Span& sp, ::HIR::TraitPath& tmp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_traitpath_needed(tpl) ? tmp = monomorphise_traitpath_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::PathParams& monomorphise_pathparams_with_opt(const Span& sp, ::HIR::PathParams& tmp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_pathparams_needed(tpl) ? tmp = monomorphise_path_params_with(sp, tpl, callback, allow_infer) : tpl);
+}
+
typedef ::std::function<bool(const ::HIR::TypeRef&)> t_cb_visit_ty;
/// Calls the provided callback on every type seen when recursing the type.
/// If the callback returns `true`, no further types are visited and the function returns `true`.
extern bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback);
+extern bool visit_path_tys_with(const ::HIR::Path& ty, t_cb_visit_ty callback);
typedef ::std::function<bool(const ::HIR::TypeRef&, ::HIR::TypeRef&)> t_cb_clone_ty;
/// Clones a type, calling the provided callback on every type (optionally providing a replacement)
extern ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback);
+extern ::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback);
// Helper for passing a group of params around
struct MonomorphState
@@ -119,3 +138,6 @@ static inline t_cb_generic monomorphise_type_get_cb(const Span& sp, const ::HIR:
}
extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct);
+
+class StaticTraitResolve;
+extern void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code);
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp
index 319124ad..7abe5532 100644
--- a/src/hir_typeck/expr_check.cpp
+++ b/src/hir_typeck/expr_check.cpp
@@ -22,14 +22,18 @@ namespace {
const ::HIR::TypeRef& ret_type;
::std::vector< const ::HIR::TypeRef*> closure_ret_types;
::std::vector<const ::HIR::ExprNode_Loop*> m_loops;
+ //const ::HIR::ExprPtr* m_cur_expr;
::HIR::SimplePath m_lang_Index;
public:
+ bool expand_erased_types;
+
ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type):
m_resolve(res),
//m_args(args),
ret_type(ret_type)
+ ,expand_erased_types(true)
{
m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index");
}
@@ -131,6 +135,7 @@ namespace {
TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type);
if(node.m_value)
{
+ check_pattern(node.m_pattern, node.m_value->m_res_type);
check_types_equal(node.span(), node.m_type, node.m_value->m_res_type);
node.m_value->visit(*this);
}
@@ -141,6 +146,10 @@ namespace {
node.m_value->visit(*this);
for(auto& arm : node.m_arms)
{
+ for(const auto& pat : arm.m_patterns)
+ {
+ check_pattern(pat, node.m_value->m_res_type);
+ }
check_types_equal(node.span(), node.m_res_type, arm.m_code->m_res_type);
arm.m_code->visit( *this );
}
@@ -149,9 +158,11 @@ namespace {
{
TRACE_FUNCTION_F(&node << " if ... { ... } else { ... }");
node.m_cond->visit( *this );
+ node.m_true->visit( *this );
check_types_equal(node.span(), node.m_res_type, node.m_true->m_res_type);
if( node.m_false )
{
+ node.m_false->visit( *this );
check_types_equal(node.span(), node.m_res_type, node.m_false->m_res_type);
}
}
@@ -208,10 +219,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);
@@ -306,11 +317,10 @@ namespace {
}
// Check castability
- TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (de),
- (
- ERROR(sp, E0000, "Invalid cast to " << dst_ty);
- ),
- (Pointer,
+ TU_MATCH_HDRA( (dst_ty.m_data), {)
+ default:
+ ERROR(sp, E0000, "Invalid cast to\n " << dst_ty << "\n from\n " << src_ty);
+ TU_ARMA(Pointer, de) {
TU_MATCH_DEF(::HIR::TypeRef::Data, (src_ty.m_data), (se),
(
ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty);
@@ -346,11 +356,40 @@ namespace {
this->check_types_equal(sp, *de.inner, *se.inner);
)
)
- ),
- (Primitive,
+ }
+ TU_ARMA(Function, de) {
+ // NOTE: cast fn() only valid from:
+ // - the same function pointer (already checked, but eventually could be a stripping of the path tag)
+ // - A capture-less closure
+ TU_MATCH_HDRA( (src_ty.m_data), {)
+ default:
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty);
+ break;
+ TU_ARMA(Function, se) {
+ if( se.is_unsafe != de.is_unsafe && se.is_unsafe )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - removing unsafe");
+ if( se.m_abi != de.m_abi )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - different ABI");
+ if( *se.m_rettype != *de.m_rettype )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - return type different");
+ if( se.m_arg_types.size() != de.m_arg_types.size() )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument count different");
+ for( size_t i = 0; i < se.m_arg_types.size(); i ++)
+ {
+ if( se.m_arg_types[i] != de.m_arg_types[i] )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument " << i << " different");
+ }
+ }
+ TU_ARMA(Closure, se) {
+ // Allowed, but won't exist after expansion
+ // TODO: Check argument types
+ }
+ }
+ }
+ TU_ARMA(Primitive, de) {
// TODO: Check cast to primitive
- )
- )
+ }
+ }
node.m_value->visit( *this );
}
@@ -362,7 +401,12 @@ namespace {
const auto& src_ty = node.m_value->m_res_type;
const auto& dst_ty = node.m_res_type;
- if( src_ty == dst_ty )
+ if( src_ty.m_data.is_Array() )
+ {
+ ASSERT_BUG(sp, dst_ty.m_data.is_Slice(), "");
+ ASSERT_BUG(sp, node.m_usage == ::HIR::ValueUsage::Unknown, "");
+ }
+ else if( src_ty == dst_ty )
{
}
else if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() )
@@ -462,6 +506,9 @@ namespace {
(Union,
BUG(sp, "Union in TupleVariant");
),
+ (ExternType,
+ BUG(sp, "ExternType in TupleVariant");
+ ),
(Struct,
ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple");
fields_ptr = &e->m_data.as_Tuple();
@@ -496,6 +543,8 @@ namespace {
if( node.m_base_value) {
check_types_equal( node.m_base_value->span(), node.m_res_type, node.m_base_value->m_res_type );
}
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
// - Create ivars in path, and set result type
const auto& ty = node.m_res_type;
@@ -506,7 +555,7 @@ namespace {
(Unbound, ),
(Opaque, ),
(Enum,
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
auto idx = enm.find_variant(var_name);
ASSERT_BUG(sp, idx != SIZE_MAX, "");
@@ -520,6 +569,9 @@ namespace {
(Union,
TODO(sp, "Union in StructLiteral");
),
+ (ExternType,
+ BUG(sp, "ExternType in StructLiteral");
+ ),
(Struct,
if( e->m_data.is_Unit() )
{
@@ -536,7 +588,7 @@ namespace {
const ::HIR::t_struct_fields& fields = *fields_ptr;
#if 1
- const auto& ty_params = node.m_path.m_params.m_types;
+ const auto& ty_params = ty_path.m_params.m_types;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
if( ge.binding == 0xFFFF ) {
@@ -609,6 +661,9 @@ namespace {
(Union,
BUG(sp, "Union with _UnitVariant");
),
+ (ExternType,
+ BUG(sp, "ExternType with _UnitVariant");
+ ),
(Struct,
assert( e->m_data.is_Unit() );
)
@@ -631,8 +686,8 @@ namespace {
const ::HIR::Function* fcn_ptr = nullptr;
::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> monomorph_cb;
- TU_MATCH(::HIR::Path::Data, (path.m_data), (e),
- (Generic,
+ TU_MATCH_HDRA( (path.m_data), {)
+ TU_ARMA(Generic, e) {
const auto& path_params = e.m_params;
const auto& fcn = m_resolve.m_crate.get_function_by_path(sp, e.m_path);
@@ -657,8 +712,8 @@ namespace {
BUG(sp, "Generic bounding out of total range");
}
};
- ),
- (UfcsKnown,
+ }
+ TU_ARMA(UfcsKnown, e) {
const auto& trait_params = e.trait.m_params;
const auto& path_params = e.params;
@@ -677,11 +732,11 @@ namespace {
fcn_ptr = &fcn;
monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params);
- ),
- (UfcsUnknown,
+ }
+ TU_ARMA(UfcsUnknown, e) {
TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?");
- ),
- (UfcsInherent,
+ }
+ TU_ARMA(UfcsInherent, e) {
// - Locate function (and impl block)
const ::HIR::TypeImpl* impl_ptr = nullptr;
m_resolve.m_crate.find_type_impls(*e.type, [&](const auto& ty)->const ::HIR::TypeRef& { return ty; },
@@ -703,14 +758,15 @@ namespace {
// NOTE: Trusts the existing cache.
- ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(), "");
+ ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(),
+ "Path impl_params cache is missized - " << e.impl_params.m_types.size() << " != " << impl_ptr->m_params.m_types.size());
auto& impl_params = e.impl_params;
// Create monomorphise callback
const auto& fcn_params = e.params;
monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params);
- )
- )
+ }
+ }
assert( fcn_ptr );
const auto& fcn = *fcn_ptr;
@@ -733,7 +789,7 @@ namespace {
rv = monomorph_cb(tpl).clone();
return true;
}
- else if( tpl.m_data.is_ErasedType() ) {
+ else if( this->expand_erased_types && tpl.m_data.is_ErasedType() ) {
const auto& e = tpl.m_data.as_ErasedType();
ASSERT_BUG(sp, e.m_index < fcn_ptr->m_code.m_erased_types.size(), "");
@@ -789,7 +845,7 @@ namespace {
// TODO: Either - Don't include the above impl bound, or change the below trait to the one that has that type
for( const auto& assoc : be.trait.m_type_bounds ) {
::HIR::GenericPath type_trait_path;
- bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path);
+ bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path);
ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait);
auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true);
@@ -825,6 +881,9 @@ namespace {
}
check_types_equal(node.span(), node.m_res_type, *e.m_rettype);
)
+ else if( node.m_trait_used == ::HIR::ExprNode_CallValue::TraitUsed::Unknown )
+ {
+ }
else
{
// 1. Look up the encoded trait
@@ -888,7 +947,7 @@ namespace {
const auto& sp = node.span();
const auto& str_ty = node.m_value->m_res_type;
- bool is_index = ( '0' <= node.m_field[0] && node.m_field[0] <= '9' );
+ bool is_index = ( '0' <= node.m_field.c_str()[0] && node.m_field.c_str()[0] <= '9' );
if( str_ty.m_data.is_Tuple() )
{
ASSERT_BUG(sp, is_index, "Non-index _Field on tuple");
@@ -1050,6 +1109,16 @@ namespace {
}
void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const
{
+ // TODO: Recurse when an erased type is encountered
+ //if( const auto* e = l.m_data.opt_ErasedType() )
+ //{
+ // return check_types_equal(sp, m_cur_expr->m_erased_types.at(e->m_index), r);
+ //}
+ //if( const auto* e = r.m_data.opt_ErasedType() )
+ //{
+ // return check_types_equal(sp, l, m_cur_expr->m_erased_types.at(e->m_index));
+ //}
+ //DEBUG(sp << " - " << l << " == " << r);
if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) {
// Diverge, matches everything.
// TODO: Is this always true?
@@ -1097,6 +1166,89 @@ namespace {
ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity);
}
}
+ void check_pattern(const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const
+ {
+ Span sp;
+ TU_MATCH_HDRA( (pat.m_data), { )
+ TU_ARMA(Any, pe) {
+ // Don't care
+ }
+ TU_ARMA(Box, pe) {
+ // TODO: Assert that `ty` is an owned_box
+ }
+ TU_ARMA(Ref, pe) {
+ // TODO: Assert that `ty` is a &-ptr
+ }
+ TU_ARMA(Tuple, pe) {
+ // TODO: Check for a matching tuple size
+ }
+ TU_ARMA(SplitTuple, pe) {
+ // TODO: Check for a matching tuple size
+ }
+ TU_ARMA(StructValue, pe) {
+ // TODO: Check that the type matches the struct
+ }
+ TU_ARMA(StructTuple, pe) {
+ // TODO: Destructure
+ }
+ TU_ARMA(Struct, pe) {
+ // TODO: Destructure
+ }
+
+ TU_ARMA(Value, pe) {
+ this->check_pattern_value(sp, pe.val, ty);
+ }
+ TU_ARMA(Range, pe) {
+ this->check_pattern_value(sp, pe.start, ty);
+ this->check_pattern_value(sp, pe.end, ty);
+ }
+ TU_ARMA(EnumValue, e) {
+ // TODO: Check type
+ }
+ TU_ARMA(EnumTuple, e) {
+ // TODO: Destructure
+ }
+ TU_ARMA(EnumStruct, e) {
+ // TODO: Destructure
+ }
+ TU_ARMA(Slice, e) {
+ // TODO: Check that the type is a Slice or Array
+ // - Array must match size
+ }
+ TU_ARMA(SplitSlice, e) {
+ // TODO: Check that the type is a Slice or Array
+ // - Array must have compatible size
+ }
+ }
+ }
+ void check_pattern_value(const Span& sp, const ::HIR::Pattern::Value& pv, const ::HIR::TypeRef& ty) const
+ {
+ TU_MATCH_HDRA( (pv), { )
+ TU_ARMA(Integer, e) {
+ if( e.type == ::HIR::CoreType::Str ) {
+ }
+ else {
+ check_types_equal(sp, ty, e.type);
+ }
+ }
+ TU_ARMA(Float, e) {
+ if( e.type == ::HIR::CoreType::Str ) {
+ }
+ else {
+ check_types_equal(sp, ty, e.type);
+ }
+ }
+ TU_ARMA(String, e) {
+ check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str));
+ }
+ TU_ARMA(ByteString, e) {
+ check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_slice(::HIR::CoreType::U8)));
+ }
+ TU_ARMA(Named, e) {
+ // TODO: Get type of the value and check equality
+ }
+ }
+ }
const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const
{
@@ -1166,6 +1318,7 @@ namespace {
ExprVisitor_Validate ev(m_resolve, tmp, item.m_type);
ev.visit_root(item.m_value);
}
+ m_resolve.expand_associated_types(Span(), item.m_type);
}
void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
//auto _ = this->m_ms.set_item_generics(item.m_params);
@@ -1210,6 +1363,13 @@ namespace {
};
}
+void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code)
+{
+ ExprVisitor_Validate ev(resolve, args, ret_ty);
+ ev.expand_erased_types = false; // TODO: Make this an argument, we don't want to do this too early
+ ev.visit_root( const_cast<::HIR::ExprPtr&>(code) );
+}
+
void Typecheck_Expressions_Validate(::HIR::Crate& crate)
{
OuterVisitor ov(crate);
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 363dfeeb..8a374946 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -11,11 +11,32 @@
#include <hir/visitor.hpp>
#include <algorithm> // std::find_if
+#include <hir_typeck/static.hpp>
#include "helpers.hpp"
#include "expr_visit.hpp"
namespace {
inline HIR::ExprNodeP mk_exprnodep(HIR::ExprNode* en, ::HIR::TypeRef ty){ en->m_res_type = mv$(ty); return HIR::ExprNodeP(en); }
+
+ inline ::HIR::SimplePath get_parent_path(const ::HIR::SimplePath& sp) {
+ auto rv = sp;
+ rv.m_components.pop_back();
+ return rv;
+ }
+ inline ::HIR::GenericPath get_parent_path(const ::HIR::GenericPath& gp) {
+ auto rv = gp.clone();
+ rv.m_path.m_components.pop_back();
+ return rv;
+ }
+
+ bool type_contains_impl_placeholder(const ::HIR::TypeRef& t) {
+ return visit_ty_with(t, [&](const auto& ty)->bool {
+ if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
+ return true;
+ }
+ return false;
+ });
+ }
}
#define NEWNODE(TY, SP, CLASS, ...) mk_exprnodep(new HIR::ExprNode##CLASS(SP ,## __VA_ARGS__), TY)
@@ -26,13 +47,14 @@ struct Context
{
public:
virtual ~Revisitor() = default;
+ virtual const Span& span() const = 0;
virtual void fmt(::std::ostream& os) const = 0;
- virtual bool revisit(Context& context) = 0;
+ virtual bool revisit(Context& context, bool is_fallback) = 0;
};
struct Binding
{
- ::std::string name;
+ RcString name;
::HIR::TypeRef ty;
//unsigned int ivar;
};
@@ -40,47 +62,58 @@ struct Context
/// Inferrence variable equalities
struct Coercion
{
+ unsigned rule_idx;
::HIR::TypeRef left_ty;
::HIR::ExprNodeP* right_node_ptr;
friend ::std::ostream& operator<<(::std::ostream& os, const Coercion& v) {
- os << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")";
+ os << "R" << v.rule_idx << " " << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")";
return os;
}
};
struct Associated
{
+ unsigned rule_idx;
Span span;
::HIR::TypeRef left_ty;
::HIR::SimplePath trait;
::HIR::PathParams params;
::HIR::TypeRef impl_ty;
- ::std::string name; // if "", no type is used (and left is ignored) - Just does trait selection
+ RcString name; // if "", no type is used (and left is ignored) - Just does trait selection
// HACK: operators are special - the result when both types are primitives is ALWAYS the lefthand side
bool is_operator;
friend ::std::ostream& operator<<(::std::ostream& os, const Associated& v) {
+ os << "R" << v.rule_idx << " ";
if( v.name == "" ) {
os << "req ty " << v.impl_ty << " impl " << v.trait << v.params;
}
else {
os << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name;
}
+ if( v.is_operator )
+ os << " - op";
return os;
}
};
struct IVarPossible
{
+ bool force_disable = false;
bool force_no_to = false;
bool force_no_from = false;
+ // Target types for coercion/unsizing (these types are known to exist in the function)
::std::vector<::HIR::TypeRef> types_coerce_to;
::std::vector<::HIR::TypeRef> types_unsize_to;
+ // Source types for coercion/unsizing (these types are known to exist in the function)
::std::vector<::HIR::TypeRef> types_coerce_from;
::std::vector<::HIR::TypeRef> types_unsize_from;
+ // Possible default types (from generic defaults)
//::std::vector<::HIR::TypeRef> types_default;
+ // Possible types from trait impls (may introduce new types)
+ ::std::vector<::HIR::TypeRef> bounded;
void reset() {
//auto tmp = mv$(this->types_default);
@@ -88,7 +121,19 @@ struct Context
//this->types_default = mv$(tmp);
}
bool has_rules() const {
- return !types_unsize_to.empty() || !types_coerce_to.empty() || !types_unsize_from.empty() || !types_coerce_from.empty() /* || !types_default.empty()*/;
+ if( !types_coerce_to.empty() )
+ return true;
+ if( !types_unsize_to.empty() )
+ return true;
+ if( !types_coerce_from.empty() )
+ return true;
+ if( !types_unsize_from.empty() )
+ return true;
+ //if( !types_default.empty() )
+ // return true;
+ if( !bounded.empty() )
+ return true;
+ return false;
}
};
@@ -98,6 +143,7 @@ struct Context
HMTypeInferrence m_ivars;
TraitResolution m_resolve;
+ unsigned next_rule_idx;
::std::vector<Coercion> link_coerce;
::std::vector<Associated> link_assoc;
/// Nodes that need revisiting (e.g. method calls when the receiver isn't known)
@@ -105,15 +151,18 @@ struct Context
/// Callback-based revisits (e.g. for slice patterns handling slices/arrays)
::std::vector< ::std::unique_ptr<Revisitor> > adv_revisits;
+ // Keep track of if an ivar is used in a context where it has to be Sized
+ // - If it is, then we can discount any unsized possibilities
::std::vector<bool> m_ivars_sized;
::std::vector< IVarPossible> possible_ivar_vals;
const ::HIR::SimplePath m_lang_Box;
- Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
+ Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& mod_path):
m_crate(crate),
- m_resolve(m_ivars, crate, impl_params, item_params),
- m_lang_Box( crate.get_lang_item_path_opt("owned_box") )
+ m_resolve(m_ivars, crate, impl_params, item_params, mod_path)
+ ,next_rule_idx( 0 )
+ ,m_lang_Box( crate.get_lang_item_path_opt("owned_box") )
{
}
@@ -164,6 +213,7 @@ struct Context
equate_types_shadow(sp, l, false);
}
void equate_types_shadow(const Span& sp, const ::HIR::TypeRef& ty, bool is_to);
+ void equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty);
/// Possible type that this ivar can coerce to
void possible_equate_type_coerce_to(unsigned int ivar_index, const ::HIR::TypeRef& t) {
@@ -191,15 +241,19 @@ struct Context
}
/// Default type
//void possible_equate_type_def(unsigned int ivar_index, const ::HIR::TypeRef& t);
+ /// Add a possible type for an ivar (which is used if only one possibility meets available bounds)
+ void possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t);
void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow);
void possible_equate_type_disable(unsigned int ivar_index, bool is_to);
+ void possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index);
// - Add a pattern binding (forcing the type to match)
- void add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
+ void handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
+ void handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
void add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, ::HIR::TypeRef type);
- void add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type);
+ void add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type);
const ::HIR::TypeRef& get_var(const Span& sp, unsigned int idx) const;
// - Add a revisit entry
@@ -224,6 +278,7 @@ namespace {
void apply_bounds_as_rules(Context& context, const Span& sp, const ::HIR::GenericParams& params_def, t_cb_generic monomorph_cb, bool is_impl_level)
{
+ TRACE_FUNCTION;
for(const auto& bound : params_def.m_bounds)
{
TU_MATCH(::HIR::GenericBound, (bound), (be),
@@ -250,7 +305,7 @@ namespace {
::HIR::GenericPath type_trait_path;
ASSERT_BUG(sp, be.trait.m_trait_ptr, "Trait pointer not set in " << be.trait.m_path);
// TODO: Store the source trait for this bound in the the bound list?
- if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path) )
+ if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path) )
BUG(sp, "Couldn't find associated type " << assoc.first << " in trait " << real_trait);
auto other_ty = monomorphise_type_with(sp, assoc.second, monomorph_cb, true);
@@ -377,11 +432,13 @@ namespace {
// --- Monomorphise the argument/return types (into current context)
for(const auto& arg : fcn.m_args) {
- DEBUG("Arg " << arg.first << ": " << arg.second);
+ TRACE_FUNCTION_FR(path << " - Arg " << arg.first << ": " << arg.second, "Arg " << arg.first << " : " << cache.m_arg_types.back());
cache.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb, false) );
}
- DEBUG("Ret " << fcn.m_return);
- cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) );
+ {
+ TRACE_FUNCTION_FR(path << " - Ret " << fcn.m_return, "Ret " << cache.m_arg_types.back());
+ cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) );
+ }
// --- Apply bounds by adding them to the associated type ruleset
apply_bounds_as_rules(context, sp, *cache.m_fcn_params, cache.m_monomorph_cb, /*is_impl_level=*/false);
@@ -520,6 +577,22 @@ namespace {
return true;
}
+ class ExprVisitor_AddIvars:
+ public HIR::ExprVisitorDef
+ {
+ Context& context;
+ public:
+ ExprVisitor_AddIvars(Context& context):
+ context(context)
+ {
+ }
+
+ void visit_type(::HIR::TypeRef& ty)
+ {
+ this->context.add_ivars(ty);
+ }
+ };
+
// -----------------------------------------------------------------------
// Enumeration visitor
//
@@ -731,7 +804,7 @@ namespace {
TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type);
this->context.add_ivars( node.m_type );
- this->context.add_binding(node.span(), node.m_pattern, node.m_type);
+ this->context.handle_pattern(node.span(), node.m_pattern, node.m_type);
if( node.m_value )
{
@@ -756,14 +829,17 @@ namespace {
{
TRACE_FUNCTION_F(&node << " match ...");
- const auto& val_type = node.m_value->m_res_type;
+ auto val_type = this->context.m_ivars.new_ivar_tr();
{
auto _ = this->push_inner_coerce_scoped(true);
this->context.add_ivars(node.m_value->m_res_type);
- // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }`
node.m_value->visit( *this );
+ // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }`
+ // - But, this can break some parts of inferrence
+ this->context.equate_types( node.span(), val_type, node.m_value->m_res_type );
+ //this->context.equate_types_coerce( node.span(), val_type, node.m_value );
}
for(auto& arm : node.m_arms)
@@ -771,7 +847,7 @@ namespace {
TRACE_FUNCTION_F("ARM " << arm.m_patterns);
for(auto& pat : arm.m_patterns)
{
- this->context.add_binding(node.span(), pat, val_type);
+ this->context.handle_pattern(node.span(), pat, val_type);
}
if( arm.m_cond )
@@ -786,6 +862,11 @@ namespace {
this->equate_types_inner_coerce(node.span(), node.m_res_type, arm.m_code);
arm.m_code->visit( *this );
}
+
+ if( node.m_arms.empty() ) {
+ DEBUG("Empty match");
+ this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_diverge());
+ }
}
void visit(::HIR::ExprNode_If& node) override
@@ -891,10 +972,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);
@@ -999,10 +1080,12 @@ namespace {
TRACE_FUNCTION_F(&node << " ... [ ... ]");
this->context.add_ivars( node.m_value->m_res_type );
+ node.m_cache.index_ty = this->context.m_ivars.new_ivar_tr();
this->context.add_ivars( node.m_index->m_res_type );
node.m_value->visit( *this );
node.m_index->visit( *this );
+ this->context.equate_types_coerce(node.m_index->span(), node.m_cache.index_ty, node.m_index);
this->context.add_revisit(node);
}
@@ -1068,8 +1151,7 @@ namespace {
}
else
{
- auto s_path = gp.m_path;
- s_path.m_components.pop_back();
+ auto s_path = get_parent_path(gp.m_path);
const auto& enm = this->context.m_crate.get_enum_by_path(sp, s_path);
fix_param_count(sp, this->context, ::HIR::TypeRef(), false, gp, enm.m_params, gp.m_params);
@@ -1110,6 +1192,9 @@ namespace {
),
(Union,
BUG(sp, "TupleVariant pointing to a union");
+ ),
+ (ExternType,
+ BUG(sp, "TupleVariant pointing to a extern type");
)
)
assert(fields_ptr);
@@ -1159,7 +1244,9 @@ namespace {
{
const auto& sp = node.span();
TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]");
- this->add_ivars_generic_path(node.span(), node.m_path);
+
+ this->add_ivars_path(node.span(), node.m_path);
+
for( auto& val : node.m_values ) {
this->context.add_ivars( val.second->m_res_type );
}
@@ -1167,8 +1254,17 @@ namespace {
this->context.add_ivars( node.m_base_value->m_res_type );
}
+ // TODO: The path can be a Ufcs (any type)
+ if( !node.m_path.m_data.is_Generic() )
+ {
+ auto t = this->context.m_resolve.expand_associated_types(sp, ::HIR::TypeRef::new_path( mv$(node.m_path), {} ));
+ node.m_path = mv$(t.m_data.as_Path().path);
+ }
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
+
// - Create ivars in path, and set result type
- const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path);
+ const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, ty_path);
this->context.equate_types(node.span(), node.m_res_type, ty);
if( node.m_base_value ) {
this->context.equate_types(node.span(), node.m_base_value->m_res_type, ty);
@@ -1179,8 +1275,9 @@ namespace {
TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e),
(Unbound, ),
(Opaque, ),
+ (ExternType, ), // Error?
(Enum,
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
auto idx = enm.find_variant(var_name);
ASSERT_BUG(sp, idx != SIZE_MAX, "");
@@ -1223,7 +1320,7 @@ namespace {
ASSERT_BUG(node.span(), fields_ptr, "");
const ::HIR::t_struct_fields& fields = *fields_ptr;
- const auto& ty_params = node.m_path.m_params.m_types;
+ const auto& ty_params = ty_path.m_params.m_types;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
if( ge.binding == 0xFFFF ) {
@@ -1247,7 +1344,7 @@ namespace {
{
const auto& name = val.first;
auto it = ::std::find_if(fields.begin(), fields.end(), [&](const auto& v)->bool{ return v.first == name; });
- ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << node.m_path);
+ ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << ty_path);
const auto& des_ty_r = it->second.ent;
auto& des_ty_cache = node.m_value_types[it - fields.begin()];
const auto* des_ty = &des_ty_r;
@@ -1407,7 +1504,7 @@ namespace {
}
// - Search in-scope trait list for traits that provide a method of this name
- const ::std::string& method_name = node.m_method;
+ const RcString& method_name = node.m_method;
::HIR::t_trait_list possible_traits;
unsigned int max_num_params = 0;
for(const auto& trait_ref : ::reverse(m_traits))
@@ -1628,8 +1725,7 @@ namespace {
} break;
case ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR: {
const auto& var_name = e.m_path.m_components.back();
- auto enum_path = e.m_path;
- enum_path.m_components.pop_back();
+ auto enum_path = get_parent_path(e.m_path);
const auto& enm = this->context.m_crate.get_enum_by_path(sp, enum_path);
fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, enm.m_params, e.m_params);
size_t idx = enm.find_variant(var_name);
@@ -1855,7 +1951,7 @@ namespace {
TRACE_FUNCTION_F(&node << " |...| ...");
for(auto& arg : node.m_args) {
this->context.add_ivars( arg.second );
- this->context.add_binding( node.span(), arg.first, arg.second );
+ this->context.handle_pattern( node.span(), arg.first, arg.second );
}
this->context.add_ivars( node.m_return );
this->context.add_ivars( node.m_code->m_res_type );
@@ -1981,7 +2077,7 @@ namespace {
const auto& ty = this->context.get_type(rty);
// TODO: Search the entire type for `!`? (What about pointers to it? or Option/Result?)
// - A correct search will search for unconditional (ignoring enums with a non-! variant) non-rawptr instances of ! in the type
- return ty.m_data.is_Diverge();// || (ty.m_data.is_Infer() && ty.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge);
+ return ty.m_data.is_Diverge();
};
assert( !node.m_nodes.empty() );
@@ -1998,6 +2094,7 @@ namespace {
diverges = false;
break;
default:
+ this->context.equate_types_from_shadow(node.span(), node.m_res_type);
return ;
}
)
@@ -2075,7 +2172,24 @@ namespace {
),
(Primitive,
// Don't have anything to contribute
- this->m_completed = true;
+ // EXCEPT: `char` can only be casted from `u8` (but what about no-op casts?)
+ // - Hint the input (default) to be `u8`
+ if( e == ::HIR::CoreType::Char )
+ {
+ if(this->m_is_fallback)
+ {
+ this->context.equate_types(sp, src_ty, ::HIR::CoreType::U8);
+ }
+
+ if( !this->context.get_type(src_ty).m_data.is_Infer() )
+ {
+ this->m_completed = true;
+ }
+ }
+ else
+ {
+ this->m_completed = true;
+ }
),
(Path,
this->context.equate_types_coerce(sp, tgt_ty, node.m_value);
@@ -2154,8 +2268,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);
@@ -2194,16 +2308,17 @@ namespace {
// TODO: In some rare cases, this ivar could be completely
// unrestricted. If in fallback mode
const auto& dst_inner = this->context.get_type(*e.inner);
- if(this->m_is_fallback)
+ if( dst_inner.m_data.is_Infer() )
{
- if( dst_inner.m_data.is_Infer() )
+ if(this->m_is_fallback)
{
+ DEBUG("- Fallback mode, assume inner types are equal");
this->context.equate_types(sp, *e.inner, *s_e.inner);
}
- }
- else if( dst_inner.m_data.is_Infer() )
- {
- return ;
+ else
+ {
+ return ;
+ }
}
else
{
@@ -2238,7 +2353,8 @@ namespace {
void visit(::HIR::ExprNode_Index& node) override {
const auto& lang_Index = this->context.m_crate.get_lang_item_path(node.span(), "index");
const auto& val_ty = this->context.get_type(node.m_value->m_res_type);
- const auto& idx_ty = this->context.get_type(node.m_index->m_res_type);
+ //const auto& idx_ty = this->context.get_type(node.m_index->m_res_type);
+ const auto& idx_ty = this->context.get_type(node.m_cache.index_ty);
TRACE_FUNCTION_F("Index: val=" << val_ty << ", idx=" << idx_ty << "");
this->context.equate_types_from_shadow(node.span(), node.m_res_type);
@@ -2255,6 +2371,9 @@ namespace {
do {
const auto& ty = this->context.get_type(*current_ty);
DEBUG("(Index): (: " << ty << ")[: " << trait_pp.m_types[0] << "]");
+ if( ty.m_data.is_Infer() ) {
+ return ;
+ }
::HIR::TypeRef possible_index_type;
::HIR::TypeRef possible_res_type;
@@ -2334,7 +2453,29 @@ namespace {
)
this->m_completed = true;
}
- void visit(::HIR::ExprNode_Emplace& node) override {
+ void visit_emplace_129(::HIR::ExprNode_Emplace& node) {
+ const auto& sp = node.span();
+ const auto& exp_ty = this->context.get_type(node.m_res_type);
+ const auto& data_ty = this->context.get_type(node.m_value->m_res_type);
+ const auto& placer_ty = this->context.get_type(node.m_place->m_res_type);
+ const auto& lang_Boxed = this->context.m_lang_Box;
+ TRACE_FUNCTION_F("exp_ty=" << exp_ty << ", data_ty=" << data_ty << ", placer_ty" << placer_ty);
+ ASSERT_BUG(sp, node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer, "1.29 mode with non-box _Emplace node");
+ ASSERT_BUG(sp, placer_ty == ::HIR::TypeRef::new_unit(), "1.29 mode with box in syntax - placer type is " << placer_ty);
+
+ ASSERT_BUG(sp, !lang_Boxed.m_components.empty(), "`owbed_box` not present when `box` operator used");
+
+ // NOTE: `owned_box` shouldn't point to anything but a struct
+ const auto& str = this->context.m_crate.get_struct_by_path(sp, lang_Boxed);
+ // TODO: Store this type to avoid having to construct it every pass
+ auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str );
+
+ // TODO: is there anyting special about this node that might need revisits?
+
+ context.equate_types(sp, exp_ty, boxed_ty);
+ this->m_completed = true;
+ }
+ void visit_emplace_119(::HIR::ExprNode_Emplace& node) {
const auto& sp = node.span();
const auto& exp_ty = this->context.get_type(node.m_res_type);
const auto& data_ty = this->context.get_type(node.m_value->m_res_type);
@@ -2352,6 +2493,8 @@ namespace {
{
// Can't do anything, the place is still unknown
DEBUG("Place unknown, wait");
+ //this->context.equate_types_to_shadow(sp, placer_ty);
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
@@ -2381,6 +2524,7 @@ namespace {
auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str );
this->context.possible_equate_type_coerce_from( exp_ty.m_data.as_Infer().index, boxed_ty );
}
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
// Assert that the expected result is a Path::Generic type.
@@ -2429,6 +2573,16 @@ namespace {
this->m_completed = true;
}
+ void visit(::HIR::ExprNode_Emplace& node) override {
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19:
+ return visit_emplace_119(node);
+ case TargetVersion::Rustc1_29:
+ return visit_emplace_129(node);
+ }
+ throw "BUG: Unhandled target version";
+ }
void visit(::HIR::ExprNode_TupleVariant& node) override {
no_revisit(node);
@@ -2441,8 +2595,9 @@ namespace {
const auto& ty_o = this->context.get_type(node.m_value->m_res_type);
TRACE_FUNCTION_F("CallValue: ty=" << ty_o);
+ //this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ this->context.equate_types_shadow_strong(node.span(), node.m_res_type);
// - Shadow (prevent ivar guessing) every parameter
- this->context.equate_types_from_shadow(node.span(), node.m_res_type);
for( const auto& arg_ty : node.m_arg_ivars ) {
this->context.equate_types_to_shadow(node.span(), arg_ty);
}
@@ -2498,6 +2653,15 @@ namespace {
// No idea yet
return ;
}
+ else if( const auto* e = ty.m_data.opt_Borrow() )
+ {
+ deref_count++;
+ ty_p = &this->context.get_type(*e->inner);
+ DEBUG("Deref " << ty << " -> " << *ty_p);
+ keep_looping = true;
+ continue;
+ }
+ // TODO: If autoderef is possible, do it and continue. Only look for impls once autoderef fails
else
{
::HIR::TypeRef fcn_args_tup;
@@ -2507,8 +2671,12 @@ namespace {
// - This will get the TraitObject impl search too
// Locate an impl of FnOnce (exists for all other Fn* traits)
+ // TODO: Sometimes there's impls that just forward for wrappers, which can lead to incorrect rules
+ // e.g. `&mut _` (where `_ = Box<...>`) later will pick the FnMut impl for `&mut T: FnMut` - but Box doesn't have those forwarding impls
+ // - Maybe just keep applying auto-deref until it's no longer possible?
unsigned int count = 0;
this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
+ // TODO: Don't accept if too fuzzy
count++;
auto tup = impl.get_trait_ty_param(0);
@@ -2524,7 +2692,7 @@ namespace {
if(count > 1) {
return;
}
- if(count == 1)
+ if( count == 1 )
{
// 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce)
@@ -2646,7 +2814,10 @@ namespace {
const auto& sp = node.span();
const auto& ty = this->context.get_type(node.m_value->m_res_type);
- TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params);
+ TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params
+ << "(" << FMT_CB(os, for( const auto& arg_node : node.m_args ) os << this->context.m_ivars.fmt_type(arg_node->m_res_type) << ", ";) << ")"
+ << " -> " << this->context.m_ivars.fmt_type(node.m_res_type)
+ );
// Make sure that no mentioned types are inferred until this method is known
this->context.equate_types_from_shadow(node.span(), node.m_res_type);
@@ -2659,14 +2830,103 @@ namespace {
// - If running in a mode after stablise (before defaults), fall
// back to trait if the inherent is still ambigious.
::std::vector<::std::pair<TraitResolution::AutoderefBorrow, ::HIR::Path>> possible_methods;
- unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method, possible_methods);
+ unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method.c_str(), possible_methods);
try_again:
if( deref_count != ~0u )
{
DEBUG("possible_methods = " << possible_methods);
if( possible_methods.empty() )
{
- ERROR(sp, E0000, "No applicable methods for {" << ty << "}." << node.m_method);
+ //ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`");
+ ERROR(sp, E0000, "No applicable methods for {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method);
+ }
+ if( possible_methods.size() > 1 )
+ {
+ // TODO: What do do when there's multiple possibilities?
+ // - Should use available information to strike them down
+ // > Try and equate the return type and the arguments, if any fail then move on to the next possibility?
+ // > ONLY if those arguments/return are generic
+ //
+ // Possible causes of multiple entries
+ // - Multiple distinct traits with the same method
+ // > If `self` is concretely known, this is an error (and shouldn't happen in well-formed code).
+ // - Multiple inherent methods on a type
+ // > These would have to have different type parmeters
+ // - Multiple trait bounds (same trait, different type params)
+ // > Guess at the type params, then discard if there's a conflict?
+ // > De-duplicate same traits?
+ //
+ //
+ // So: To be able to prune the list, we need to check the type parameters for the trait/type/impl
+
+ // De-duplcate traits in this list.
+ // - If the self type and the trait name are the same, replace with an entry using placeholder
+ // ivars (node.m_trait_param_ivars)
+ for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1)
+ {
+ if( it_1->first != possible_methods.front().first )
+ {
+ it_1 = possible_methods.erase(it_1) - 1;
+ }
+ }
+ for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1)
+ {
+ if( !it_1->second.m_data.is_UfcsKnown() )
+ continue;
+ bool was_found = false;
+ auto& e1 = it_1->second.m_data.as_UfcsKnown();
+ for(auto it_2 = it_1 + 1; it_2 != possible_methods.end(); ++ it_2)
+ {
+ if( !it_2->second.m_data.is_UfcsKnown() )
+ continue;
+ if( it_2->second == it_1->second ) {
+ it_2 = possible_methods.erase(it_2) - 1;
+ continue ;
+ }
+ const auto& e2 = it_2->second.m_data.as_UfcsKnown();
+
+ // TODO: If the trait is the same, but the type differs, pick the first?
+ if( e1.trait == e2.trait ) {
+ DEBUG("Duplicate trait, different type - " << e1.trait << " for " << *e1.type << " or " << *e2.type << ", picking the first");
+ it_2 = possible_methods.erase(it_2) - 1;
+ continue ;
+ }
+ if( *e1.type != *e2.type )
+ continue;
+ if( e1.trait.m_path != e2.trait.m_path )
+ continue;
+ assert( !(e1.trait.m_params == e2.trait.m_params) );
+
+ DEBUG("Duplicate trait in possible_methods - " << it_1->second << " and " << it_2->second);
+ if( !was_found )
+ {
+ was_found = true;
+ const auto& ivars = node.m_trait_param_ivars;
+ unsigned int n_params = e1.trait.m_params.m_types.size();
+ assert(n_params <= ivars.size());
+ ::HIR::PathParams trait_params;
+ trait_params.m_types.reserve( n_params );
+ for(unsigned int i = 0; i < n_params; i++) {
+ trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) );
+ //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound");
+ }
+ // If one of these was already using the placeholder ivars, then maintain the one with the palceholders
+ if( e1.trait.m_params != trait_params )
+ {
+ e1.trait.m_params = mv$(trait_params);
+ }
+
+ it_2 = possible_methods.erase(it_2) - 1;
+ }
+ }
+ }
+ }
+ assert( !possible_methods.empty() );
+ if( possible_methods.size() != 1 && possible_methods.front().second.m_data.is_UfcsKnown() )
+ {
+ DEBUG("- Multiple options, deferring");
+ // TODO: If the type is fully known, then this is an error.
+ return;
}
auto& ad_borrow = possible_methods.front().first;
auto& fcn_path = possible_methods.front().second;
@@ -2705,6 +2965,7 @@ namespace {
)
if( this->m_is_fallback && fcn_path.m_data.is_UfcsInherent() )
{
+ //possible_methods.erase(possible_methods.begin());
while( !possible_methods.empty() && possible_methods.front().second.m_data.is_UfcsInherent() )
{
possible_methods.erase(possible_methods.begin());
@@ -2790,7 +3051,8 @@ namespace {
const auto& field_name = node.m_field;
TRACE_FUNCTION_F("(Field) name=" << field_name << ", ty = " << this->context.m_ivars.fmt_type(node.m_value->m_res_type));
- this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ //this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ this->context.equate_types_shadow_strong(node.span(), node.m_res_type);
::HIR::TypeRef out_type;
@@ -2800,6 +3062,7 @@ namespace {
const auto* current_ty = &node.m_value->m_res_type;
::std::vector< ::HIR::TypeRef> deref_res_types;
+ // TODO: autoderef_find_field?
do {
const auto& ty = this->context.m_ivars.get_type(*current_ty);
if( ty.m_data.is_Infer() ) {
@@ -2810,7 +3073,7 @@ namespace {
DEBUG("Hit unbound path, returning early");
return ;
}
- if( this->context.m_resolve.find_field(node.span(), ty, field_name, out_type) ) {
+ if( this->context.m_resolve.find_field(node.span(), ty, field_name.c_str(), out_type) ) {
this->context.equate_types(node.span(), node.m_res_type, out_type);
break;
}
@@ -2877,7 +3140,7 @@ namespace {
void no_revisit(::HIR::ExprNode& node) {
BUG(node.span(), "Node revisit unexpected - " << typeid(node).name());
}
- };
+ }; // class ExprVisitor_Revisit
// -----------------------------------------------------------------------
// Post-inferrence visitor
@@ -2916,7 +3179,7 @@ namespace {
void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override {
auto& node = *node_ptr;
const char* node_ty = typeid(node).name();
- TRACE_FUNCTION_FR(&node << " " << &node << " " << node_ty << " : " << node.m_res_type, node_ty);
+ TRACE_FUNCTION_FR(&node_ptr << " " << &node << " " << node_ty << " : " << node.m_res_type, &node << " " << node_ty);
this->check_type_resolved_top(node.span(), node.m_res_type);
DEBUG(node_ty << " : = " << node.m_res_type);
::HIR::ExprVisitorDef::visit_node_ptr(node_ptr);
@@ -2961,6 +3224,23 @@ namespace {
::HIR::ExprVisitorDef::visit_pattern(sp, pat);
}
+ void visit(::HIR::ExprNode_Block& node) override {
+ ::HIR::ExprVisitorDef::visit(node);
+ if( node.m_value_node )
+ {
+ check_types_equal(node.span(), node.m_res_type, node.m_value_node->m_res_type);
+ }
+ // If the last node diverges (yields `!`) then this block can yield `!` (or anything)
+ else if( ! node.m_nodes.empty() && node.m_nodes.back()->m_res_type == ::HIR::TypeRef::new_diverge() )
+ {
+ }
+ else
+ {
+ // Non-diverging (empty, or with a non-diverging last node) blocks must yield `()`
+ check_types_equal(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit());
+ }
+ }
+
void visit(::HIR::ExprNode_Let& node) override {
this->check_type_resolved_top(node.span(), node.m_type);
::HIR::ExprVisitorDef::visit(node);
@@ -3002,7 +3282,7 @@ namespace {
this->check_type_resolved_genericpath(node.span(), node.m_path);
}
void visit(::HIR::ExprNode_StructLiteral& node) override {
- this->check_type_resolved_pp(node.span(), node.m_path.m_params, ::HIR::TypeRef());
+ this->check_type_resolved_path(node.span(), node.m_path);
for(auto& ty : node.m_value_types) {
if( ty != ::HIR::TypeRef() ) {
this->check_type_resolved_top(node.span(), ty);
@@ -3169,7 +3449,148 @@ namespace {
)
)
}
- };
+
+ void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const
+ {
+ DEBUG(sp << " - " << l << " == " << r);
+ if( r.m_data.is_Diverge() ) {
+ // Diverge on the right is always valid
+ // - NOT on the left, because `!` can become everything, but nothing can become `!`
+ }
+ else if( l != r ) {
+ ERROR(sp, E0000, "Type mismatch - " << l << " != " << r);
+ }
+ else {
+ // All good
+ }
+ }
+ }; // class ExprVisitor_Apply
+
+ class ExprVisitor_Print:
+ public ::HIR::ExprVisitor
+ {
+ const Context& context;
+ ::std::ostream& m_os;
+ public:
+ ExprVisitor_Print(const Context& context, ::std::ostream& os):
+ context(context),
+ m_os(os)
+ {}
+
+ void visit(::HIR::ExprNode_Block& node) override {
+ m_os << "_Block {" << context.m_ivars.fmt_type(node.m_nodes.back()->m_res_type) << "}";
+ }
+ void visit(::HIR::ExprNode_Asm& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Return& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Let& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Loop& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_LoopControl& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Match& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_If& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Assign& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_BinOp& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UniOp& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Borrow& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Cast& node) override {
+ m_os << "_Cast {" << context.m_ivars.fmt_type(node.m_value->m_res_type) << "}";
+ }
+ void visit(::HIR::ExprNode_Unsize& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Index& node) override {
+ m_os << "_Index {" << fmt_res_ty(*node.m_value) << "}[{" << fmt_res_ty(*node.m_index) << "}]";
+ }
+ void visit(::HIR::ExprNode_Deref& node) override {
+ m_os << "_Deref {" << fmt_res_ty(*node.m_value) << "}";
+ }
+ void visit(::HIR::ExprNode_Emplace& node) override {
+ m_os << "_Emplace(" << fmt_res_ty(*node.m_value) << " in " << fmt_res_ty(*node.m_place) << ")";
+ }
+
+ void visit(::HIR::ExprNode_TupleVariant& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_CallPath& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_CallValue& node) override {
+ m_os << "_CallValue {" << fmt_res_ty(*node.m_value) << "}(";
+ for(const auto& arg : node.m_args)
+ m_os << "{" << fmt_res_ty(*arg) << "}, ";
+ m_os << ")";
+ }
+ void visit(::HIR::ExprNode_CallMethod& node) override {
+ m_os << "_CallMethod {" << fmt_res_ty(*node.m_value) << "}." << node.m_method << "(";
+ for(const auto& arg : node.m_args)
+ m_os << "{" << fmt_res_ty(*arg) << "}, ";
+ m_os << ")";
+ }
+ void visit(::HIR::ExprNode_Field& node) override {
+ m_os << "_Field {" << fmt_res_ty(*node.m_value) << "}." << node.m_field;
+ }
+
+ void visit(::HIR::ExprNode_Literal& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UnitVariant& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_PathValue& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Variable& node) override {
+ no_revisit(node);
+ }
+
+ void visit(::HIR::ExprNode_StructLiteral& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UnionLiteral& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Tuple& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_ArrayList& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_ArraySized& node) override {
+ no_revisit(node);
+ }
+
+ void visit(::HIR::ExprNode_Closure& node) override {
+ no_revisit(node);
+ }
+ private:
+ HMTypeInferrence::FmtType fmt_res_ty(const ::HIR::ExprNode& n) {
+ return context.m_ivars.fmt_type(n.m_res_type);
+ }
+ void no_revisit(::HIR::ExprNode& n) {
+ throw "";
+ }
+ }; // class ExprVisitor_Print
}
@@ -3183,13 +3604,14 @@ void Context::dump() const {
m_ivars.dump();
DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes, " << adv_revisits.size() << " callbacks");
for(const auto& v : link_coerce) {
- DEBUG(v);
+ //DEBUG(v);
+ DEBUG("R" << v.rule_idx << " " << this->m_ivars.fmt_type(v.left_ty) << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << this->m_ivars.fmt_type((*v.right_node_ptr)->m_res_type) << ")");
}
for(const auto& v : link_assoc) {
DEBUG(v);
}
for(const auto& v : to_visit) {
- DEBUG(&*v << " " << typeid(*v).name() << " -> " << this->m_ivars.fmt_type(v->m_res_type));
+ DEBUG(&*v << " " << FMT_CB(os, { ExprVisitor_Print ev(*this, os); v->visit(ev); }) << " -> " << this->m_ivars.fmt_type(v->m_res_type));
}
for(const auto& v : adv_revisits) {
DEBUG(FMT_CB(ss, v->fmt(ss);));
@@ -3207,24 +3629,21 @@ void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR
// Instantly apply equality
TRACE_FUNCTION_F(li << " == " << ri);
- visit_ty_with(ri, [&](const auto& ty)->bool {
- if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
- BUG(sp, "Type contained an impl placeholder parameter - " << ri);
- }
- return false;
- });
- visit_ty_with(li, [&](const auto& ty)->bool {
- if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
- BUG(sp, "Type contained an impl placeholder parameter - " << li);
- }
- return false;
- });
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(ri), "Type contained an impl placeholder parameter - " << ri);
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(li), "Type contained an impl placeholder parameter - " << li);
::HIR::TypeRef l_tmp;
::HIR::TypeRef r_tmp;
const auto& l_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(li), l_tmp);
const auto& r_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(ri), r_tmp);
+ if( l_t.m_data.is_Diverge() && !r_t.m_data.is_Infer() ) {
+ return ;
+ }
+ if( r_t.m_data.is_Diverge() && !l_t.m_data.is_Infer() ) {
+ return;
+ }
+
equate_types_inner(sp, l_t, r_t);
}
@@ -3494,7 +3913,809 @@ void Context::add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb,
}
// NOTE: Mutates the pattern to add ivars to contained paths
-void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
+void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
+{
+ TRACE_FUNCTION_F("pat = " << pat << ", type = " << type);
+
+ // TODO: 1.29 includes "match ergonomics" which allows automatic insertion of borrow/deref when matching
+ // - Handling this will make pattern matching slightly harder (all patterns needing revisist)
+ // - BUT: New bindings will still be added as usualin this pass.
+ // - Any use of `&` (or `ref`?) in the pattern disables match ergonomics for the entire pattern.
+ // - Does `box` also do this disable?
+ //
+ //
+ // - Add a counter to each pattern indicting how many implicit borrows/derefs are applied.
+ // - When this function is called, check if the pattern is eligable for pattern auto-ref/deref
+ // - Detect if the pattern uses & or ref. If it does, then invoke the existing code
+ // - Otherwise, register a revisit for the pattern
+
+
+ struct H2 {
+ static bool has_ref_or_borrow(const Span& sp, const ::HIR::Pattern& pat) {
+ // TODO: Turns out that this isn't valid. See libsyntax 1.29
+ // - ref `rustc-1.29.0-src/src/libsyntax/print/pprust.rs` 2911, `&Option` matched with `Some(ref foo)`
+ //if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) {
+ // return true;
+ //}
+ if( pat.m_data.is_Ref() ) {
+ return true;
+ }
+ bool rv = false;
+ TU_MATCHA( (pat.m_data), (e),
+ (Any,
+ ),
+ (Value,
+ ),
+ (Range,
+ ),
+ (Box,
+ rv |= H2::has_ref_or_borrow(sp, *e.sub);
+ ),
+ (Ref,
+ rv |= H2::has_ref_or_borrow(sp, *e.sub);
+ ),
+ (Tuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (SplitTuple,
+ for(auto& subpat : e.leading) {
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ }
+ ),
+ (Slice,
+ for(auto& sub : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ ),
+ (SplitSlice,
+ for(auto& sub : e.leading)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ for(auto& sub : e.trailing)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ ),
+
+ // - Enums/Structs
+ (StructValue,
+ ),
+ (StructTuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (Struct,
+ for( auto& field_pat : e.sub_patterns )
+ rv |= H2::has_ref_or_borrow(sp, field_pat.second);
+ ),
+ (EnumValue,
+ ),
+ (EnumTuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (EnumStruct,
+ for( auto& field_pat : e.sub_patterns )
+ rv |= H2::has_ref_or_borrow(sp, field_pat.second);
+ )
+ )
+ return rv;
+ }
+ };
+
+ // 1. Determine if this pattern can apply auto-ref/deref
+ if( pat.m_data.is_Any() ) {
+ // `_` pattern, no destructure/match, so no auto-ref/deref
+ // - TODO: Does this do auto-borrow too?
+ if( pat.m_binding.is_valid() ) {
+ this->add_binding_inner(sp, pat.m_binding, type.clone());
+ }
+ return ;
+ }
+
+ // NOTE: Even if the top-level is a binding, and even if the top-level type is fully known, match ergonomics
+ // still applies.
+ if( TARGETVER_1_29 ) { //&& ! H2::has_ref_or_borrow(sp, pat) ) {
+ // There's not a `&` or `ref` in the pattern, and we're targeting 1.29
+ // - Run the match ergonomics handler
+ // TODO: Default binding mode can be overridden back to "move" with `mut`
+
+ struct MatchErgonomicsRevisit:
+ public Revisitor
+ {
+ Span sp;
+ ::HIR::TypeRef m_outer_ty;
+ ::HIR::Pattern& m_pattern;
+ ::HIR::PatternBinding::Type m_outer_mode;
+
+ mutable ::std::vector<::HIR::TypeRef> m_temp_ivars;
+ mutable ::HIR::TypeRef m_possible_type;
+
+ MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move):
+ sp(mv$(sp)), m_outer_ty(mv$(outer)),
+ m_pattern(pat),
+ m_outer_mode(binding_mode)
+ {}
+
+ const Span& span() const override {
+ return sp;
+ }
+ void fmt(::std::ostream& os) const override {
+ os << "MatchErgonomicsRevisit { " << m_pattern << " : " << m_outer_ty << " }";
+ }
+ bool revisit(Context& context, bool is_fallback_mode) override {
+ TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty << (is_fallback_mode ? " (fallback)": ""));
+ m_outer_ty = context.m_resolve.expand_associated_types(sp, mv$(m_outer_ty));
+ return this->revisit_inner_real(context, m_pattern, m_outer_ty, m_outer_mode, is_fallback_mode);
+ }
+ // TODO: Recurse into inner patterns, creating new revisitors?
+ // - OR, could just recurse on it.
+ //
+ // Recusring incurs costs on every iteration, but is less expensive the first time around
+ // New revisitors are cheaper when inferrence takes multiple iterations, but takes longer first time.
+ bool revisit_inner(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const
+ {
+ if( !revisit_inner_real(context, pattern, type, binding_mode, false) )
+ {
+ DEBUG("Add revisit for " << pattern << " : " << type << "(mode = " << (int)binding_mode << ")");
+ context.add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pattern, binding_mode } )) );
+ }
+ return true;
+ }
+ ::HIR::TypeRef get_possible_type_val(Context& context, ::HIR::Pattern::Value& pv) const
+ {
+ TU_MATCH_HDR( (pv), {)
+ TU_ARM(pv, Integer, ve) {
+ if( ve.type == ::HIR::CoreType::Str ) {
+ return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Integer);
+ }
+ return ve.type;
+ }
+ TU_ARM(pv, Float, ve) {
+ if( ve.type == ::HIR::CoreType::Str ) {
+ return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Float);
+ }
+ return ve.type;
+ }
+ TU_ARM(pv, String, ve) {
+ return ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str);
+ }
+ TU_ARM(pv, ByteString, ve) {
+ // TODO: ByteString patterns can match either &[u8] or &[u8; N]
+ //return ::HIR::TypeRef::new_borrow(
+ // ::HIR::BorrowType::Shared,
+ // ::HIR::TypeRef::new_slice(::HIR::CoreType::U8)
+ // );
+ return ::HIR::TypeRef();
+ }
+ TU_ARM(pv, Named, ve) {
+ // TODO: Look up the path and get the type
+ return ::HIR::TypeRef();
+ }
+ }
+ throw "";
+ }
+ const ::HIR::TypeRef& get_possible_type(Context& context, ::HIR::Pattern& pattern) const
+ {
+ if( m_possible_type == ::HIR::TypeRef() )
+ {
+ ::HIR::TypeRef possible_type;
+ // Get a potential type from the pattern, and set as a possibility.
+ // - Note, this is only if no derefs were applied
+ TU_MATCH_HDR( (pattern.m_data), { )
+ TU_ARM(pattern.m_data, Any, pe) {
+ // No type information.
+ }
+ TU_ARM(pattern.m_data, Value, pe) {
+ possible_type = get_possible_type_val(context, pe.val);
+ }
+ TU_ARM(pattern.m_data, Range, pe) {
+ possible_type = get_possible_type_val(context, pe.start);
+ if( possible_type == ::HIR::TypeRef() ) {
+ possible_type = get_possible_type_val(context, pe.end);
+ }
+ else {
+ // TODO: Check that the type from .end matches .start
+ }
+ }
+ TU_ARM(pattern.m_data, Box, pe) {
+ // TODO: Get type info (Box<_>) ?
+ // - Is this possible? Shouldn't a box pattern disable ergonomics?
+ }
+ TU_ARM(pattern.m_data, Ref, pe) {
+ BUG(sp, "Match ergonomics - & pattern");
+ }
+ TU_ARM(pattern.m_data, Tuple, e) {
+ // Get type info `(T, U, ...)`
+ if( m_temp_ivars.size() != e.sub_patterns.size() ) {
+ for(size_t i = 0; i < e.sub_patterns.size(); i ++)
+ m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() );
+ }
+ decltype(m_temp_ivars) tuple;
+ for(const auto& ty : m_temp_ivars)
+ tuple.push_back(ty.clone());
+ possible_type = ::HIR::TypeRef( ::std::move(tuple) );
+ }
+ TU_ARM(pattern.m_data, SplitTuple, pe) {
+ // Can't get type information, tuple size is unkown
+ }
+ TU_ARM(pattern.m_data, Slice, e) {
+ // Can be either a [T] or [T; n]. Can't provide a hint
+ }
+ TU_ARM(pattern.m_data, SplitSlice, pe) {
+ // Can be either a [T] or [T; n]. Can't provide a hint
+ }
+ TU_ARM(pattern.m_data, StructValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, StructTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, Struct, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, EnumValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ TU_ARM(pattern.m_data, EnumTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ TU_ARM(pattern.m_data, EnumStruct, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ }
+ m_possible_type = ::std::move(possible_type);
+ }
+ return m_possible_type;
+ }
+ bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode, bool is_fallback) const
+ {
+ TRACE_FUNCTION_F(pattern << " : " << type);
+
+ // Binding applies to the raw input type (not after dereferencing)
+ if( pattern.m_binding.is_valid() )
+ {
+ // - Binding present, use the current binding mode
+ if( pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move )
+ {
+ pattern.m_binding.m_type = binding_mode;
+ }
+ ::HIR::TypeRef tmp;
+ const ::HIR::TypeRef* binding_type = nullptr;
+ switch(pattern.m_binding.m_type)
+ {
+ case ::HIR::PatternBinding::Type::Move:
+ binding_type = &type;
+ break;
+ case ::HIR::PatternBinding::Type::MutRef:
+ // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T)
+ binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type.clone()));
+ break;
+ case ::HIR::PatternBinding::Type::Ref:
+ // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T)
+ binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type.clone()));
+ break;
+ default:
+ TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type);
+ }
+ assert(binding_type);
+ context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), *binding_type);
+ }
+
+ // For `_` patterns, there's nothing to match, so they just succeed with no derefs
+ if( pattern.m_data.is_Any() )
+ {
+ return true;
+ }
+
+ if( auto* pe = pattern.m_data.opt_Ref() )
+ {
+ // Require a &-ptr (hard requirement), then visit sub-pattern
+ auto inner_ty = context.m_ivars.new_ivar_tr();
+ auto new_ty = ::HIR::TypeRef::new_borrow( pe->type, inner_ty.clone() );
+ context.equate_types(sp, type, new_ty);
+
+ return this->revisit_inner( context, *pe->sub, inner_ty, binding_mode );
+ }
+
+ // If the type is a borrow, then count derefs required for the borrow
+ // - If the first non-borrow inner is an ivar, return false
+ unsigned n_deref = 0;
+ ::HIR::BorrowType bt = ::HIR::BorrowType::Owned;
+ const auto* ty_p = &context.get_type(type);
+ while( ty_p->m_data.is_Borrow() ) {
+ DEBUG("bt " << bt << ", " << ty_p->m_data.as_Borrow().type);
+ bt = ::std::min(bt, ty_p->m_data.as_Borrow().type);
+ ty_p = &context.get_type( *ty_p->m_data.as_Borrow().inner );
+ n_deref ++;
+ }
+ DEBUG("- " << n_deref << " derefs of class " << bt << " to get " << *ty_p);
+ if( ty_p->m_data.is_Infer() || TU_TEST1(ty_p->m_data, Path, .binding.is_Unbound()) )
+ {
+ // Still pure infer, can't do anything
+ // - What if it's a literal?
+
+ // TODO: Don't do fallback if the ivar is marked as being hard blocked
+ if( const auto* te = ty_p->m_data.opt_Infer() )
+ {
+ if( te->index < context.possible_ivar_vals.size()
+ && context.possible_ivar_vals[te->index].force_disable
+ )
+ {
+ MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern);
+ return false;
+ }
+ }
+
+ // If there's no dereferences done, then add a possible unsize type
+ const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern);
+ if( possible_type != ::HIR::TypeRef() )
+ {
+ DEBUG("n_deref = " << n_deref << ", possible_type = " << possible_type);
+ const ::HIR::TypeRef* possible_type_p = &possible_type;
+ // Unwrap borrows as many times as we've already dereferenced
+ for(size_t i = 0; i < n_deref && possible_type_p; i ++) {
+ if( const auto* te = possible_type_p->m_data.opt_Borrow() ) {
+ possible_type_p = &*te->inner;
+ }
+ else {
+ possible_type_p = nullptr;
+ }
+ }
+ if( possible_type_p )
+ {
+ const auto& possible_type = *possible_type_p;
+ if( const auto* te = ty_p->m_data.opt_Infer() )
+ {
+ context.possible_equate_type_unsize_to(te->index, possible_type);
+ }
+ else if( is_fallback )
+ {
+ DEBUG("Fallback equate " << possible_type);
+ context.equate_types(sp, *ty_p, possible_type);
+ }
+ else
+ {
+ }
+
+ //if( is_fallback )
+ //{
+ // DEBUG("Possible equate " << possible_type);
+ // context.equate_types( sp, *ty_p, possible_type );
+ //}
+ }
+ }
+
+ // Visit all inner bindings and disable coercion fallbacks on them.
+ MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern);
+ return false;
+ }
+ const auto& ty = *ty_p;
+
+ // Here we have a known type and binding mode for this pattern
+ // - Time to handle this pattern then recurse into sub-patterns
+
+ // Store the deref count in the pattern.
+ pattern.m_implicit_deref_count = n_deref;
+ // Determine the new binding mode from the borrow type
+ switch(bt)
+ {
+ case ::HIR::BorrowType::Owned:
+ // No change
+ break;
+ case ::HIR::BorrowType::Unique:
+ switch(binding_mode)
+ {
+ case ::HIR::PatternBinding::Type::Move:
+ case ::HIR::PatternBinding::Type::MutRef:
+ binding_mode = ::HIR::PatternBinding::Type::MutRef;
+ break;
+ case ::HIR::PatternBinding::Type::Ref:
+ // No change
+ break;
+ }
+ break;
+ case ::HIR::BorrowType::Shared:
+ binding_mode = ::HIR::PatternBinding::Type::Ref;
+ break;
+ }
+
+ bool rv = false;
+ TU_MATCH_HDR( (pattern.m_data), { )
+ TU_ARM(pattern.m_data, Any, pe) {
+ // no-op
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Value, pe) {
+ // no-op?
+ if( pe.val.is_String() || pe.val.is_ByteString() ) {
+ ASSERT_BUG(sp, pattern.m_implicit_deref_count >= 1, "");
+ pattern.m_implicit_deref_count -= 1;
+ }
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Range, pe) {
+ // no-op?
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Box, pe) {
+ // Box<T>
+ if( TU_TEST2(ty.m_data, Path, .path.m_data, Generic, .m_path == context.m_lang_Box) )
+ {
+ const auto& path = ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& inner = path.m_params.m_types.at(0);
+ rv = this->revisit_inner(context, *pe.sub, inner, binding_mode);
+ }
+ else
+ {
+ TODO(sp, "Match ergonomics - box pattern - Non Box<T> type: " << ty);
+ //auto inner = this->m_ivars.new_ivar_tr();
+ //this->handle_pattern_direct_inner(sp, *e.sub, inner);
+ //::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) };
+ //this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) );
+ }
+ }
+ TU_ARM(pattern.m_data, Ref, pe) {
+ BUG(sp, "Match ergonomics - & pattern");
+ }
+ TU_ARM(pattern.m_data, Tuple, e) {
+ if( !ty.m_data.is_Tuple() ) {
+ ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty);
+ }
+ const auto& te = ty.m_data.as_Tuple();
+ if( e.sub_patterns.size() != te.size() ) {
+ ERROR(sp, E0000, "Tuple pattern with an incorrect number of fields, expected " << e.sub_patterns.size() << "-tuple, got " << ty);
+ }
+
+ rv = true;
+ for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ rv &= this->revisit_inner(context, e.sub_patterns[i], te[i], binding_mode);
+ }
+ TU_ARM(pattern.m_data, SplitTuple, pe) {
+ if( !ty.m_data.is_Tuple() ) {
+ ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty);
+ }
+ const auto& te = ty.m_data.as_Tuple();
+ if( pe.leading.size() + pe.trailing.size() > te.size() ) {
+ ERROR(sp, E0000, "Split-tuple pattern with an incorrect number of fields, expected at most " << (pe.leading.size() + pe.trailing.size()) << "-tuple, got " << te.size());
+ }
+ pe.total_size = te.size();
+ rv = true;
+ for(size_t i = 0; i < pe.leading.size(); i++)
+ rv &= this->revisit_inner(context, pe.leading[i], te[i], binding_mode);
+ for(size_t i = 0; i < pe.trailing.size(); i++)
+ rv &= this->revisit_inner(context, pe.trailing[i], te[te.size() - pe.trailing.size() + i], binding_mode);
+ }
+ TU_ARM(pattern.m_data, Slice, e) {
+ const ::HIR::TypeRef* slice_inner;
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
+ slice_inner = &*te.inner;
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
+ slice_inner = &*te.inner;
+ )
+ else {
+ ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty);
+ }
+ rv = true;
+ for(auto& sub : e.sub_patterns)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ }
+ TU_ARM(pattern.m_data, SplitSlice, pe) {
+ const ::HIR::TypeRef* slice_inner;
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
+ slice_inner = &*te.inner;
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
+ slice_inner = &*te.inner;
+ )
+ else {
+ ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty);
+ }
+ rv = true;
+ for(auto& sub : pe.leading)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ // TODO: Extra bind
+ for(auto& sub : pe.trailing)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ }
+ TU_ARM(pattern.m_data, StructValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, StructTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+
+ assert(e.binding);
+ const auto& str = *e.binding;
+
+ // - assert check from earlier pass
+ ASSERT_BUG(sp, str.m_data.is_Tuple(), "Struct-tuple pattern on non-Tuple struct");
+ const auto& sd = str.m_data.as_Tuple();
+ const auto& params = e.path.m_params;
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true;
+ for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ {
+ /*const*/ auto& sub_pat = e.sub_patterns[i];
+ const auto& field_type = sd[i].ent;
+ const auto& var_ty = maybe_monomorph(field_type);
+ rv &= this->revisit_inner(context, sub_pat, var_ty, binding_mode);
+ }
+ }
+ TU_ARM(pattern.m_data, Struct, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+ assert(e.binding);
+ const auto& str = *e.binding;
+
+ //if( ! e.is_wildcard() )
+ if( e.sub_patterns.empty() )
+ {
+ // TODO: Check the field count?
+ rv = true;
+ }
+ else
+ {
+ // - assert check from earlier pass
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct");
+ const auto& sd = str.m_data.as_Named();
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true;
+ for( auto& field_pat : e.sub_patterns )
+ {
+ unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin();
+ if( f_idx == sd.size() ) {
+ ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first);
+ }
+ const ::HIR::TypeRef& field_type = maybe_monomorph(sd[f_idx].second.ent);
+ rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode);
+ }
+ }
+ }
+ TU_ARM(pattern.m_data, EnumValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, EnumTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ assert(e.binding_ptr);
+ const auto& enm = *e.binding_ptr;
+ const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
+ const auto& tup_var = str.m_data.as_Tuple();
+
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ if( e.sub_patterns.size() != tup_var.size() ) {
+ ERROR(sp, E0000, "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size() );
+ }
+
+ rv = true; // &= below ensures that all must be complete to return complete
+ for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ {
+ const auto& var_ty = maybe_monomorph(tup_var[i].ent);
+ rv &= this->revisit_inner(context, e.sub_patterns[i], var_ty, binding_mode);
+ }
+ }
+ TU_ARM(pattern.m_data, EnumStruct, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ assert(e.binding_ptr);
+
+ const auto& enm = *e.binding_ptr;
+ const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
+ const auto& tup_var = str.m_data.as_Named();
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true; // &= below ensures that all must be complete to return complete
+ for( auto& field_pat : e.sub_patterns )
+ {
+ unsigned int f_idx = ::std::find_if( tup_var.begin(), tup_var.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - tup_var.begin();
+ if( f_idx == tup_var.size() ) {
+ ERROR(sp, E0000, "Enum variant " << e.path << " doesn't have a field " << field_pat.first);
+ }
+ const ::HIR::TypeRef& field_type = maybe_monomorph(tup_var[f_idx].second.ent);
+ rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode);
+ }
+ }
+ }
+ return rv;
+ }
+
+ static void disable_possibilities_on_bindings(const Span& sp, Context& context, const ::HIR::Pattern& pat)
+ {
+ if( pat.m_binding.is_valid() ) {
+ const auto& pb = pat.m_binding;
+ //context.equate_types_from_shadow(sp, context.get_var(sp, pb.m_slot));
+ context.equate_types_shadow_strong(sp, context.get_var(sp, pb.m_slot));
+ }
+ TU_MATCHA( (pat.m_data), (e),
+ (Any,
+ ),
+ (Value,
+ ),
+ (Range,
+ ),
+ (Box,
+ disable_possibilities_on_bindings(sp, context, *e.sub);
+ ),
+ (Ref,
+ disable_possibilities_on_bindings(sp, context, *e.sub);
+ ),
+ (Tuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (SplitTuple,
+ for(auto& subpat : e.leading) {
+ disable_possibilities_on_bindings(sp, context, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ disable_possibilities_on_bindings(sp, context, subpat);
+ }
+ ),
+ (Slice,
+ for(auto& sub : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, sub);
+ ),
+ (SplitSlice,
+ for(auto& sub : e.leading)
+ disable_possibilities_on_bindings(sp, context, sub);
+ for(auto& sub : e.trailing)
+ disable_possibilities_on_bindings(sp, context, sub);
+ ),
+
+ // - Enums/Structs
+ (StructValue,
+ ),
+ (StructTuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (Struct,
+ for(auto& field_pat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, field_pat.second);
+ ),
+ (EnumValue,
+ ),
+ (EnumTuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (EnumStruct,
+ for(auto& field_pat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, field_pat.second);
+ )
+ )
+ }
+ static void create_bindings(const Span& sp, Context& context, ::HIR::Pattern& pat)
+ {
+ if( pat.m_binding.is_valid() ) {
+ const auto& pb = pat.m_binding;
+ context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() );
+ // TODO: Ensure that there's no more bindings below this?
+ // - I'll leave the option open, MIR generation should handle cases where there's multiple borrows
+ // or moves.
+ }
+ TU_MATCH_HDRA( (pat.m_data), { )
+ TU_ARMA(Any, e) {
+ }
+ TU_ARMA(Value, e) {
+ }
+ TU_ARMA(Range, e) {
+ }
+ TU_ARMA(Box, e) {
+ create_bindings(sp, context, *e.sub);
+ }
+ TU_ARMA(Ref, e) {
+ create_bindings(sp, context, *e.sub);
+ }
+ TU_ARMA(Tuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(SplitTuple, e) {
+ for(auto& subpat : e.leading) {
+ create_bindings(sp, context, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ create_bindings(sp, context, subpat);
+ }
+ }
+ TU_ARMA(Slice, e) {
+ for(auto& sub : e.sub_patterns)
+ create_bindings(sp, context, sub);
+ }
+ TU_ARMA(SplitSlice, e) {
+ for(auto& sub : e.leading)
+ create_bindings(sp, context, sub);
+ if( e.extra_bind.is_valid() ) {
+ const auto& pb = e.extra_bind;
+ context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() );
+ }
+ for(auto& sub : e.trailing)
+ create_bindings(sp, context, sub);
+ }
+
+ // - Enums/Structs
+ TU_ARMA(StructValue, e) {
+ }
+ TU_ARMA(StructTuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(Struct, e) {
+ for(auto& field_pat : e.sub_patterns)
+ create_bindings(sp, context, field_pat.second);
+ }
+ TU_ARMA(EnumValue, e) {
+ }
+ TU_ARMA(EnumTuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(EnumStruct, e) {
+ for(auto& field_pat : e.sub_patterns)
+ create_bindings(sp, context, field_pat.second);
+ }
+ }
+ }
+ };
+ // - Create variables, assigning new ivars for all of them.
+ MatchErgonomicsRevisit::create_bindings(sp, *this, pat);
+ // - Add a revisit for the outer pattern (saving the current target type as well as the pattern)
+ DEBUG("Handle match ergonomics - " << pat << " with " << type);
+ this->add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pat } )) );
+ return ;
+ }
+
+ // ---
+ this->handle_pattern_direct_inner(sp, pat, type);
+}
+
+void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
{
TRACE_FUNCTION_F("pat = " << pat << ", type = " << type);
@@ -3504,7 +4725,6 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
// TODO: Bindings aren't allowed within another binding
}
-
struct H {
static void handle_value(Context& context, const Span& sp, const ::HIR::TypeRef& type, const ::HIR::Pattern::Value& val) {
TU_MATCH(::HIR::Pattern::Value, (val), (v),
@@ -3561,13 +4781,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
if( te.path.m_data.is_Generic() && te.path.m_data.as_Generic().m_path == m_lang_Box ) {
// Box<T>
const auto& inner = te.path.m_data.as_Generic().m_params.m_types.at(0);
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
break ;
}
)
auto inner = this->m_ivars.new_ivar_tr();
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) };
this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) );
),
@@ -3577,11 +4797,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
if( te.type != e.type ) {
ERROR(sp, E0000, "Pattern-type mismatch, &-ptr mutability mismatch");
}
- this->add_binding(sp, *e.sub, *te.inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, *te.inner);
)
else {
auto inner = this->m_ivars.new_ivar_tr();
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
this->equate_types(sp, type, ::HIR::TypeRef::new_borrow( e.type, mv$(inner) ));
}
),
@@ -3594,14 +4814,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
}
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
- this->add_binding(sp, e.sub_patterns[i], te[i] );
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], te[i] );
)
else {
::std::vector< ::HIR::TypeRef> sub_types;
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) {
sub_types.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, e.sub_patterns[i], sub_types[i] );
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], sub_types[i] );
}
this->equate_types(sp, ty, ::HIR::TypeRef( mv$(sub_types) ));
}
@@ -3614,11 +4834,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
unsigned int tup_idx = 0;
for(auto& subpat : e.leading) {
- this->add_binding(sp, subpat, te[tup_idx++]);
+ this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]);
}
tup_idx = te.size() - e.trailing.size();
for(auto& subpat : e.trailing) {
- this->add_binding(sp, subpat, te[tup_idx++]);
+ this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]);
}
// TODO: Should this replace the pattern with a non-split?
@@ -3634,12 +4854,12 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
leading_tys.reserve(e.leading.size());
for(auto& subpat : e.leading) {
leading_tys.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, subpat, leading_tys.back());
+ this->handle_pattern_direct_inner(sp, subpat, leading_tys.back());
}
::std::vector<::HIR::TypeRef> trailing_tys;
for(auto& subpat : e.trailing) {
trailing_tys.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, subpat, trailing_tys.back());
+ this->handle_pattern_direct_inner(sp, subpat, trailing_tys.back());
}
struct SplitTuplePatRevisit:
@@ -3657,10 +4877,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
m_pat_total_size(pat_total_size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override {
os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }";
}
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(m_outer_ty);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te,
return false;
@@ -3690,16 +4913,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const auto& ty = this->get_type(type);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, *te.inner );
+ this->handle_pattern_direct_inner(sp, sub, *te.inner );
)
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, *te.inner );
+ this->handle_pattern_direct_inner(sp, sub, *te.inner );
)
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te,
auto inner = this->m_ivars.new_ivar_tr();
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, inner);
+ this->handle_pattern_direct_inner(sp, sub, inner);
struct SlicePatRevisit:
public Revisitor
@@ -3713,8 +4936,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), size(size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; }
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(type);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
context.equate_types(sp, *te.inner, inner);
@@ -3788,8 +5014,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), var_ty(mv$(var_ty)), min_size(size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<<var_ty<<", " << min_size; }
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(this->type);
if( ty.m_data.is_Infer() )
return false;
@@ -3827,9 +5056,9 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
}
for(auto& sub : e.leading)
- this->add_binding( sp, sub, inner );
+ this->handle_pattern_direct_inner( sp, sub, inner );
for(auto& sub : e.trailing)
- this->add_binding( sp, sub, inner );
+ this->handle_pattern_direct_inner( sp, sub, inner );
),
// - Enums/Structs
@@ -3856,10 +5085,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const auto& field_type = sd[i].ent;
if( monomorphise_type_needed(field_type) ) {
auto var_ty = monomorphise_type(sp, str.m_params, params, field_type);
- this->add_binding(sp, sub_pat, var_ty);
+ this->handle_pattern_direct_inner(sp, sub_pat, var_ty);
}
else {
- this->add_binding(sp, sub_pat, field_type);
+ this->handle_pattern_direct_inner(sp, sub_pat, field_type);
}
}
),
@@ -3867,7 +5096,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
this->add_ivars_params( e.path.m_params );
this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
- if( e.sub_patterns.empty() )
+ if( e.is_wildcard() )
return ;
assert(e.binding);
@@ -3887,20 +5116,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const ::HIR::TypeRef& field_type = sd[f_idx].second.ent;
if( monomorphise_type_needed(field_type) ) {
auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type);
- this->add_binding(sp, field_pat.second, field_type_mono);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono);
}
else {
- this->add_binding(sp, field_pat.second, field_type);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type);
}
}
),
(EnumValue,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
assert(e.binding_ptr);
const auto& enm = *e.binding_ptr;
@@ -3912,12 +5137,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
),
(EnumTuple,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
-
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
assert(e.binding_ptr);
const auto& enm = *e.binding_ptr;
const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
@@ -3933,21 +5153,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
{
if( monomorphise_type_needed(tup_var[i].ent) ) {
auto var_ty = monomorphise_type(sp, enm.m_params, params, tup_var[i].ent);
- this->add_binding(sp, e.sub_patterns[i], var_ty);
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], var_ty);
}
else {
- this->add_binding(sp, e.sub_patterns[i], tup_var[i].ent);
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], tup_var[i].ent);
}
}
),
(EnumStruct,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
-
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
if( e.sub_patterns.empty() )
return ;
@@ -3967,10 +5182,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent;
if( monomorphise_type_needed(field_type) ) {
auto field_type_mono = monomorphise_type(sp, enm.m_params, params, field_type);
- this->add_binding(sp, field_pat.second, field_type_mono);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono);
}
else {
- this->add_binding(sp, field_pat.second, field_type);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type);
}
}
)
@@ -3981,9 +5196,10 @@ void Context::equate_types_coerce(const Span& sp, const ::HIR::TypeRef& l, ::HIR
this->m_ivars.get_type(l);
// - Just record the equality
this->link_coerce.push_back(Coercion {
+ this->next_rule_idx ++,
l.clone(), &node_ptr
});
- DEBUG("equate_types_coerce(" << this->link_coerce.back() << ")");
+ DEBUG("++ " << this->link_coerce.back());
this->m_ivars.mark_change();
}
void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool is_to)
@@ -4025,6 +5241,46 @@ void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool
)
)
}
+void Context::equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty)
+{
+ // TODO: Would like to use visit_ty_with in a way that can be told to not recurse (for non-Generic paths)
+ TU_MATCH_DEF(::HIR::TypeRef::Data, (this->get_type(ty).m_data), (e),
+ (
+ // TODO: Shadow sub-types too
+ ),
+ (Path,
+ TU_MATCH_DEF( ::HIR::Path::Data, (e.path.m_data), (pe),
+ (
+ ),
+ (Generic,
+ for(const auto& sty : pe.m_params.m_types)
+ this->equate_types_shadow_strong(sp, sty);
+ )
+ )
+ ),
+ (Tuple,
+ for(const auto& sty : e)
+ this->equate_types_shadow_strong(sp, sty);
+ ),
+ (Borrow,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Array,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Slice,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Closure,
+ for(const auto& aty : e.m_arg_types)
+ this->equate_types_shadow_strong(sp, aty);
+ this->equate_types_shadow_strong(sp, *e.m_rettype);
+ ),
+ (Infer,
+ this->possible_equate_type_disable_strong(sp, e.index);
+ )
+ )
+}
void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::SimplePath& trait, ::HIR::PathParams pp, const ::HIR::TypeRef& impl_ty, const char *name, bool is_op)
{
for(const auto& a : this->link_assoc)
@@ -4046,6 +5302,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const
return ;
}
this->link_assoc.push_back(Associated {
+ this->next_rule_idx ++,
sp,
l.clone(),
@@ -4055,7 +5312,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const
name,
is_op
});
- DEBUG("(" << this->link_assoc.back() << ")");
+ DEBUG("++ " << this->link_assoc.back());
this->m_ivars.mark_change();
}
void Context::add_revisit(::HIR::ExprNode& node) {
@@ -4101,6 +5358,10 @@ void Context::require_sized(const Span& sp, const ::HIR::TypeRef& ty_)
// Already checked by type_is_sized
params_def = nullptr;
),
+ (ExternType,
+ static ::HIR::GenericParams empty_params;
+ params_def = &empty_params;
+ ),
(Enum,
params_def = &pb->m_params;
),
@@ -4168,6 +5429,41 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef
);
list.push_back( t.clone() );
}
+void Context::possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t) {
+ {
+ ::HIR::TypeRef ty_l;
+ ty_l.m_data.as_Infer().index = ivar_index;
+ const auto& real_ty = m_ivars.get_type(ty_l);
+ if( real_ty != ty_l )
+ {
+ DEBUG("IVar " << ivar_index << " is actually " << real_ty);
+ return ;
+ }
+
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(t), "Type contained an impl placeholder parameter - " << t);
+ }
+
+ if( ivar_index >= possible_ivar_vals.size() ) {
+ possible_ivar_vals.resize( ivar_index + 1 );
+ }
+ auto& ent = possible_ivar_vals[ivar_index];
+ for(const auto& e : ent.bounded)
+ {
+ if( e == t )
+ {
+ if( t.m_data.is_Infer() )
+ DEBUG(ivar_index << " duplicate bounded " << t << " " << this->m_ivars.get_type(t));
+ else
+ DEBUG(ivar_index << " duplicate bounded " << t);
+ return ;
+ }
+ }
+ ent.bounded.push_back( t.clone() );
+ if( t.m_data.is_Infer() )
+ DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t));
+ else
+ DEBUG(ivar_index << " bounded as " << t);
+}
void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) {
DEBUG(ivar_index << " ?= ?? (" << (is_to ? "to" : "from") << ")");
{
@@ -4187,14 +5483,30 @@ void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to)
ent.force_no_from = true;
}
}
+void Context::possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index)
+{
+ DEBUG(ivar_index << " = ??");
+ {
+ ::HIR::TypeRef ty_l;
+ ty_l.m_data.as_Infer().index = ivar_index;
+ ASSERT_BUG(sp, m_ivars.get_type(ty_l).m_data.is_Infer(), "possible_equate_type_disable_strong on known ivar");
+ }
+
+ if( ivar_index >= possible_ivar_vals.size() ) {
+ possible_ivar_vals.resize( ivar_index + 1 );
+ }
+ auto& ent = possible_ivar_vals[ivar_index];
+ ent.force_disable = true;
+}
-void Context::add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type) {
+void Context::add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type) {
DEBUG("(" << index << " " << name << " : " << type << ")");
assert(index != ~0u);
if( m_bindings.size() <= index )
m_bindings.resize(index+1);
if( m_bindings[index].name == "" ) {
m_bindings[index] = Binding { name, mv$(type) };
+ this->require_sized(sp, m_bindings[index].ty);
}
else {
ASSERT_BUG(sp, m_bindings[index].name == name, "");
@@ -4299,6 +5611,7 @@ namespace {
{
DEBUG("- Moving into block");
assert( p->m_value_node );
+ // Block result and the inner node's result must be the same type
ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, p->m_value_node->m_res_type),
"Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(p->m_value_node->m_res_type));
// - Override the the result type to the desired result
@@ -4347,8 +5660,11 @@ namespace {
};
// TODO: Add a (two?) callback(s) that handle type equalities (and possible equalities) so this function doesn't have to mutate the context
- CoerceResult check_unsize_tys(Context& context, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr)
+ CoerceResult check_unsize_tys(Context& context_mut_r, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr, bool allow_mutate=true)
{
+ Context* context_mut = (allow_mutate ? &context_mut_r : nullptr);
+ const Context& context = context_mut_r;
+
const auto& dst = context.m_ivars.get_type(dst_raw);
const auto& src = context.m_ivars.get_type(src_raw);
TRACE_FUNCTION_F("dst=" << dst << ", src=" << src);
@@ -4386,8 +5702,11 @@ namespace {
DEBUG("Literal ivars");
return CoerceResult::Equality;
}
- context.possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst);
- context.possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src);
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst);
+ context_mut->possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src);
+ }
DEBUG("Both ivars");
return CoerceResult::Unknown;
}
@@ -4399,31 +5718,62 @@ namespace {
DEBUG("Literal with primitive");
return CoerceResult::Equality;
}
- context.possible_equate_type_unsize_from(dep->index, src);
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_from(dep->index, src);
+ }
DEBUG("Dst ivar");
return CoerceResult::Unknown;
}
else if(const auto* sep = src.m_data.opt_Infer())
{
- if(sep->is_lit() && !dst.m_data.is_TraitObject())
+ if(sep->is_lit())
{
- // Literal to anything other than a trait object must be an equality
- DEBUG("Literal with primitive");
- return CoerceResult::Equality;
+ if( !dst.m_data.is_TraitObject())
+ {
+ // Literal to anything other than a trait object must be an equality
+ DEBUG("Literal with primitive");
+ return CoerceResult::Equality;
+ }
+ else
+ {
+ // Fall through
+ }
+ }
+ else
+ {
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_to(sep->index, dst);
+ }
+ DEBUG("Src is ivar (" << src << "), return Unknown");
+ return CoerceResult::Unknown;
}
- context.possible_equate_type_unsize_to(sep->index, dst);
- DEBUG("Src ivar");
- return CoerceResult::Unknown;
}
else
{
// Neither side is an ivar, keep going.
}
+ // If either side is an unbound path, then return Unknown
+ if( TU_TEST1(src.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Source unbound path");
+ return CoerceResult::Unknown;
+ }
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Destination unbound path");
+ return CoerceResult::Unknown;
+ }
+
// Array unsize (quicker than going into deref search)
if(dst.m_data.is_Slice() && src.m_data.is_Array())
{
- context.equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner);
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner);
+ }
if(node_ptr_ptr)
{
// TODO: Insert deref (instead of leading to a _Unsize op)
@@ -4457,10 +5807,9 @@ namespace {
// Deref coercions
// - If right can be dereferenced to left
- if(node_ptr_ptr)
+ if(node_ptr_ptr || !allow_mutate)
{
DEBUG("-- Deref coercions");
- auto& node_ptr = *node_ptr_ptr;
::HIR::TypeRef tmp_ty;
const ::HIR::TypeRef* out_ty_p = &src;
unsigned int count = 0;
@@ -4470,9 +5819,32 @@ namespace {
const auto& out_ty = context.m_ivars.get_type(*out_ty_p);
count += 1;
- if( out_ty.m_data.is_Infer() && !out_ty.m_data.as_Infer().is_lit() ) {
- // Hit a _, so can't keep going
- break;
+ if( const auto* sep = out_ty.m_data.opt_Infer() )
+ {
+ if( !sep->is_lit() )
+ {
+ // Hit a _, so can't keep going
+ if( context_mut )
+ {
+ // Could also be any deref chain of the destination type
+ ::HIR::TypeRef tmp_ty2;
+ const ::HIR::TypeRef* d_ty_p = &dst;
+ context_mut->possible_equate_type_unsize_to(sep->index, dst);
+ for(unsigned int i = 0; i < count && (d_ty_p = context.m_resolve.autoderef(sp, *d_ty_p, tmp_ty2)); i ++)
+ {
+ context_mut->possible_equate_type_unsize_to(sep->index, *d_ty_p);
+ }
+ }
+ DEBUG("Src derefs to ivar (" << src << "), return Unknown");
+ return CoerceResult::Unknown;
+ }
+ // Literal infer, keep going (but remember how many times we dereferenced?)
+ }
+
+ if( TU_TEST1(out_ty.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Src derefed to unbound type (" << out_ty << "), return Unknown");
+ return CoerceResult::Unknown;
}
types.push_back( out_ty.clone() );
@@ -4491,11 +5863,17 @@ namespace {
continue ;
}
DEBUG("Same tag and fuzzy match - assuming " << dst << " == " << out_ty);
- context.equate_types(sp, dst, out_ty);
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, dst, out_ty);
+ }
),
(Slice,
// Equate!
- context.equate_types(sp, dst, out_ty);
+ if(context_mut)
+ {
+ context_mut->equate_types(sp, dst, out_ty);
+ }
// - Fall through
)
)
@@ -4505,21 +5883,25 @@ namespace {
}
}
- add_coerce_borrow(context, node_ptr, types.back(), [&](auto& node_ptr)->void {
- // node_ptr = node that yeilds ty_src
- assert( count == types.size() );
- for(unsigned int i = 0; i < types.size(); i ++ )
- {
- auto span = node_ptr->span();
- // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire.
- ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions");
- auto ty = mv$(types[i]);
- node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) ));
- DEBUG("- Deref " << &*node_ptr << " -> " << ty);
- node_ptr->m_res_type = mv$(ty);
- context.m_ivars.get_type(node_ptr->m_res_type);
- }
- });
+ if( context_mut && node_ptr_ptr )
+ {
+ auto& node_ptr = *node_ptr_ptr;
+ add_coerce_borrow(*context_mut, node_ptr, types.back(), [&](auto& node_ptr)->void {
+ // node_ptr = node that yeilds ty_src
+ assert( count == types.size() );
+ for(unsigned int i = 0; i < types.size(); i ++ )
+ {
+ auto span = node_ptr->span();
+ // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire.
+ ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions");
+ auto ty = mv$(types[i]);
+ node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) ));
+ DEBUG("- Deref " << &*node_ptr << " -> " << ty);
+ node_ptr->m_res_type = mv$(ty);
+ context.m_ivars.get_type(node_ptr->m_res_type);
+ }
+ });
+ }
return CoerceResult::Custom;
}
@@ -4542,9 +5924,12 @@ namespace {
}
const auto& tys_d = dep->m_trait.m_path.m_params.m_types;
const auto& tys_s = sep->m_trait.m_path.m_params.m_types;
- for(size_t i = 0; i < tys_d.size(); i ++)
+ if( context_mut )
{
- context.equate_types(sp, tys_d[i], tys_s.at(i));
+ for(size_t i = 0; i < tys_d.size(); i ++)
+ {
+ context_mut->equate_types(sp, tys_d[i], tys_s.at(i));
+ }
}
// 2. Destination markers must be a strict subset
@@ -4573,76 +5958,35 @@ namespace {
// Check for trait impl
if( trait.m_path != ::HIR::SimplePath() )
{
- ImplRef best_impl;
- unsigned int count = 0;
- bool found = context.m_resolve.find_trait_impls(sp, trait.m_path, trait.m_params, src, [&](auto impl, auto cmp) {
- DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl);
- count ++;
- best_impl = mv$(impl);
- return cmp == ::HIR::Compare::Equal;
- });
- if( count == 0 )
+ // Just call equate_types_assoc to add the required bounds.
+ if( context_mut )
{
- // TODO: Get a better idea of when there won't ever be an applicable impl
- if( !context.m_ivars.type_contains_ivars(src) ) {
- ERROR(sp, E0000, "The trait " << dep->m_trait << " is not implemented for " << src);
- }
- DEBUG("No impl, but there may eventaully be one");
- return CoerceResult::Unknown;
- }
- if( !found )
- {
- if(count > 1)
- {
- DEBUG("Defer as there are multiple applicable impls");
- return CoerceResult::Unknown;
- }
-
- if( best_impl.has_magic_params() ) {
- DEBUG("Defer as there were magic parameters");
- return CoerceResult::Unknown;
- }
-
- // TODO: Get a better way of equating these that doesn't require getting copies of the impl's types
- context.equate_types(sp, src, best_impl.get_impl_type());
- auto args = best_impl.get_trait_params();
- assert(trait.m_params.m_types.size() == args.m_types.size());
- for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++)
+ for(const auto& tyb : dep->m_trait.m_type_bounds)
{
- context.equate_types(sp, trait.m_params.m_types[i], args.m_types[i]);
+ context_mut->equate_types_assoc(sp, tyb.second, trait.m_path, trait.m_params.clone(), src, tyb.first.c_str(), false);
}
- for(const auto& tyb : dep->m_trait.m_type_bounds)
+ if( dep->m_trait.m_type_bounds.empty() )
{
- auto ty = best_impl.get_type(tyb.first.c_str());
- if( ty != ::HIR::TypeRef() )
- {
- context.equate_types(sp, tyb.second, ty);
- }
- else
- {
- // Error? Log? ...
- DEBUG("Associated type " << tyb.first << " not present in impl, can't equate");
- }
+ context_mut->add_trait_bound(sp, src, trait.m_path, trait.m_params.clone());
}
}
+ else
+ {
+ // TODO: Should this check?
+ }
}
- for(const auto& marker : dep->m_markers)
+ if( context_mut )
{
- bool found = context.m_resolve.find_trait_impls(sp, marker.m_path, marker.m_params, src, [&](auto impl, auto cmp) {
- DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl);
- return cmp == ::HIR::Compare::Equal;
- });
- // TODO: Allow fuzz and equate same as above?
- if( !found )
+ for(const auto& marker : dep->m_markers)
{
- // TODO: Get a better idea of when there won't ever be an applicable impl
- if( !context.m_ivars.type_contains_ivars(src) ) {
- ERROR(sp, E0000, "The trait " << marker << " is not implemented for " << src);
- }
- return CoerceResult::Unknown;
+ context_mut->add_trait_bound(sp, src, marker.m_path, marker.m_params.clone());
}
}
+ else
+ {
+ // TODO: Should this check?
+ }
// Add _Unsize operator
return CoerceResult::Unsize;
@@ -4673,13 +6017,23 @@ namespace {
unsigned int count = 0;
::HIR::PathParams pp { dst.clone() };
- bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count](auto impl, auto cmp){
+ bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count,&context](auto impl, auto cmp){
DEBUG("[check_unsize_tys] Found impl " << impl << (cmp == ::HIR::Compare::Fuzzy ? " (fuzzy)" : ""));
- if( impl.more_specific_than(best_impl) )
+ if( !impl.overlaps_with(context.m_crate, best_impl) )
{
- best_impl = mv$(impl);
+ // No overlap, count it as a new possibility
+ if( count == 0 )
+ best_impl = mv$(impl);
count ++;
}
+ else if( impl.more_specific_than(best_impl) )
+ {
+ best_impl = mv$(impl);
+ }
+ else
+ {
+ // Less specific
+ }
// TODO: Record the best impl (if fuzzy) and equate params
return cmp != ::HIR::Compare::Fuzzy;
});
@@ -4691,13 +6045,17 @@ namespace {
{
auto pp = best_impl.get_trait_params();
DEBUG("Fuzzy, best was Unsize" << pp);
- context.equate_types(sp, dst, pp.m_types.at(0));
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, dst, pp.m_types.at(0));
+ }
return CoerceResult::Unsize;
}
else
{
// TODO: Fuzzy?
//context.equate_types(sp, *e.inner, *s_e.inner);
+ DEBUG("Multiple impls");
}
}
@@ -4718,6 +6076,13 @@ namespace {
(Opaque,
// Handled above in bounded
),
+ (ExternType,
+ // Must be equal
+ if( sbe == dbe )
+ {
+ return CoerceResult::Equality;
+ }
+ ),
(Enum,
// Must be equal
if( sbe == dbe )
@@ -4740,7 +6105,7 @@ namespace {
{
const auto& isrc = se.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param);
const auto& idst = de.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param);
- return check_unsize_tys(context, sp, idst, isrc, nullptr);
+ return check_unsize_tys(context_mut_r, sp, idst, isrc, nullptr, allow_mutate);
}
else
{
@@ -4755,9 +6120,17 @@ namespace {
)
}
- DEBUG("Reached end of check_unsize_tys, return Unknown");
+ // If the destination is an Unbound path, return Unknown
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Unbound destination");
+ return CoerceResult::Unknown;
+ }
+
+
+ DEBUG("Reached end of check_unsize_tys, return Equality");
// TODO: Determine if this unsizing could ever happen.
- return CoerceResult::Unknown;
+ return CoerceResult::Equality;
}
/// Checks if two types can be a valid coercion
@@ -4864,15 +6237,23 @@ namespace {
// - Recurse/unsize inner value
if( src.m_data.is_Infer() && TU_TEST2(dst.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_src = H::make_pruned(context, dst);
context.equate_types(sp, src, new_src);
+#else
+ context.possible_equate_type_coerce_to(src.m_data.as_Infer().index, dst);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
if( dst.m_data.is_Infer() && TU_TEST2(src.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_dst = H::make_pruned(context, src);
context.equate_types(sp, dst, new_dst);
+#else
+ context.possible_equate_type_coerce_from(dst.m_data.as_Infer().index, src);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
@@ -4904,6 +6285,11 @@ namespace {
}
}
+ // If either side is an unbound UFCS, can't know yet
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) || TU_TEST1(src.m_data, Path, .binding.is_Unbound()) )
+ {
+ return CoerceResult::Unknown;
+ }
// Any other type, check for pointer
// - If not a pointer, return Equality
@@ -5049,6 +6435,7 @@ namespace {
// If the coercion is of a block, do the reborrow on the last node of the block
// - Cleans up the dumped MIR and prevents needing a reborrow elsewhere.
+ // - TODO: Alter the block's result types
::HIR::ExprNodeP* npp = node_ptr_ptr;
while( auto* p = dynamic_cast< ::HIR::ExprNode_Block*>(&**npp) )
{
@@ -5058,7 +6445,7 @@ namespace {
ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, src),
"Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(src)
);
- p->m_res_type = new_type.clone();
+ p->m_res_type = dst.clone();
npp = &p->m_value_node;
}
::HIR::ExprNodeP& node_ptr = *npp;
@@ -5077,17 +6464,27 @@ namespace {
context.m_ivars.mark_change();
// Continue on with coercion (now that node_ptr is updated)
- switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, node_ptr_ptr) )
+ switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, &node_ptr) )
{
case CoerceResult::Unknown:
- return CoerceResult::Unknown;
+ // Add new coercion at the new inner point
+ if( &node_ptr != node_ptr_ptr )
+ {
+ DEBUG("Unknown check_unsize_tys after autoderef - " << dst << " := " << node_ptr->m_res_type);
+ context.equate_types_coerce(sp, dst, node_ptr);
+ return CoerceResult::Custom;
+ }
+ else
+ {
+ return CoerceResult::Unknown;
+ }
case CoerceResult::Custom:
return CoerceResult::Custom;
case CoerceResult::Equality:
context.equate_types(sp, *dep->inner, *se.inner);
return CoerceResult::Custom;
case CoerceResult::Unsize:
- DEBUG("- NEWNODE _Unsize " << &*node_ptr << " -> " << dst);
+ DEBUG("- NEWNODE _Unsize " << &node_ptr << " " << &*node_ptr << " -> " << dst);
auto span = node_ptr->span();
node_ptr = NEWNODE( dst.clone(), span, _Unsize, mv$(node_ptr), dst.clone() );
return CoerceResult::Custom;
@@ -5116,6 +6513,75 @@ namespace {
return CoerceResult::Equality;
}
}
+ else if( src.m_data.is_Closure() )
+ {
+ const auto& se = src.m_data.as_Closure();
+ if( dst.m_data.is_Function() )
+ {
+ const auto& de = dst.m_data.as_Function();
+ auto& node_ptr = *node_ptr_ptr;
+ auto span = node_ptr->span();
+ if( de.m_abi != ABI_RUST ) {
+ ERROR(span, E0000, "Cannot use closure for extern function pointer");
+ }
+ if( de.m_arg_types.size() != se.m_arg_types.size() ) {
+ ERROR(span, E0000, "Mismatched argument count coercing closure to fn(...)");
+ }
+ for(size_t i = 0; i < de.m_arg_types.size(); i++)
+ {
+ context.equate_types(sp, de.m_arg_types[i], se.m_arg_types[i]);
+ }
+ context.equate_types(sp, *de.m_rettype, *se.m_rettype);
+ node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() );
+ return CoerceResult::Custom;
+ }
+ else if( const auto* dep = dst.m_data.opt_Infer() )
+ {
+ // Prevent inferrence of argument/return types
+ for(const auto& at : se.m_arg_types)
+ context.equate_types_to_shadow(sp, at);
+ context.equate_types_to_shadow(sp, *se.m_rettype);
+ // Add as a possiblity
+ context.possible_equate_type_coerce_from(dep->index, src);
+ return CoerceResult::Unknown;
+ }
+ else
+ {
+ return CoerceResult::Equality;
+ }
+ }
+ else if( const auto* se = src.m_data.opt_Function() )
+ {
+ if( const auto* de = dst.m_data.opt_Function() )
+ {
+ auto& node_ptr = *node_ptr_ptr;
+ auto span = node_ptr->span();
+ DEBUG("Function pointer coercion");
+ // ABI must match
+ if( se->m_abi != de->m_abi )
+ return CoerceResult::Equality;
+ // const can be removed
+ //if( se->is_const != de->is_const && de->is_const ) // Error going TO a const function pointer
+ // return CoerceResult::Equality;
+ // unsafe can be added
+ if( se->is_unsafe != de->is_unsafe && se->is_unsafe ) // Error going FROM an unsafe function pointer
+ return CoerceResult::Equality;
+ // argument/return types must match
+ if( de->m_arg_types.size() != se->m_arg_types.size() )
+ return CoerceResult::Equality;
+ for(size_t i = 0; i < de->m_arg_types.size(); i++)
+ {
+ context.equate_types(sp, de->m_arg_types[i], se->m_arg_types[i]);
+ }
+ context.equate_types(sp, *de->m_rettype, *se->m_rettype);
+ node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() );
+ return CoerceResult::Custom;
+ }
+ else
+ {
+ return CoerceResult::Equality;
+ }
+ }
else
{
// TODO: ! should be handled above or in caller?
@@ -5158,8 +6624,6 @@ namespace {
const auto& sp = v.span;
TRACE_FUNCTION_F(v);
- ::HIR::TypeRef possible_impl_ty;
- ::HIR::PathParams possible_params;
::HIR::TypeRef output_type;
struct H {
@@ -5217,13 +6681,34 @@ namespace {
// - This generates an exact equation.
if( v.left_ty != ::HIR::TypeRef() )
{
- context.equate_types_from_shadow(sp, v.left_ty);
+ context.equate_types_shadow_strong(sp, v.left_ty);
+ }
+
+ // HACK? Soft-prevent inferrence of the param types
+ for(const auto& t : v.params.m_types)
+ {
+ context.equate_types_to_shadow(sp, t);
+ }
+
+ // If the impl type is an unbounded ivar, and there's no trait args - don't bother searching
+ if( const auto* e = context.m_ivars.get_type(v.impl_ty).m_data.opt_Infer() )
+ {
+ // TODO: ?
+ if( !e->is_lit() && v.params.m_types.empty() )
+ {
+ return false;
+ }
}
// Locate applicable trait impl
unsigned int count = 0;
DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty));
- ImplRef best_impl;
+ struct Possibility {
+ ::HIR::TypeRef impl_ty;
+ ::HIR::PathParams params;
+ ImplRef impl_ref;
+ };
+ ::std::vector<Possibility> possible_impls;
bool found = context.m_resolve.find_trait_impls(sp, v.trait, v.params, v.impl_ty,
[&](auto impl, auto cmp) {
DEBUG("[check_associated] Found cmp=" << cmp << " " << impl);
@@ -5231,7 +6716,6 @@ namespace {
auto out_ty_o = impl.get_type(v.name.c_str());
if( out_ty_o == ::HIR::TypeRef() )
{
- //BUG(sp, "Getting associated type '" << v.name << "' which isn't in " << v.trait << " (" << ty << ")");
out_ty_o = ::HIR::TypeRef(::HIR::Path( v.impl_ty.clone(), ::HIR::GenericPath(v.trait, v.params.clone()), v.name, ::HIR::PathParams() ));
}
out_ty_o = context.m_resolve.expand_associated_types(sp, mv$(out_ty_o));
@@ -5249,6 +6733,7 @@ namespace {
}
// if solid or fuzzy, leave as-is
output_type = mv$( out_ty_o );
+ DEBUG("[check_associated] cmp = " << cmp << " (2)");
}
if( cmp == ::HIR::Compare::Equal ) {
// NOTE: Sometimes equal can be returned when it's not 100% equal (TODO)
@@ -5265,47 +6750,59 @@ namespace {
count += 1;
DEBUG("[check_associated] - (possible) " << impl);
- if( possible_impl_ty == ::HIR::TypeRef() ) {
+ if( possible_impls.empty() ) {
DEBUG("[check_associated] First - " << impl);
- possible_impl_ty = impl.get_impl_type();
- possible_params = impl.get_trait_params();
- best_impl = mv$(impl);
+ possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) });
}
- // TODO: If there is an existing impl, determine if this is part of the same specialisation tree
+ // If there is an existing impl, determine if this is part of the same specialisation tree
// - If more specific, replace. If less, ignore.
- #if 1
// NOTE: `overlaps_with` (should be) reflective
- else if( impl.overlaps_with(context.m_crate, best_impl) )
+ else
{
- DEBUG("[check_associated] - Overlaps with existing - " << best_impl);
- // if not more specific than the existing best, ignore.
- if( ! impl.more_specific_than(best_impl) )
+ bool was_used = false;
+ for(auto& possible_impl : possible_impls)
{
- DEBUG("[check_associated] - Less specific than existing");
- // NOTE: This picks the _least_ specific impl
- possible_impl_ty = impl.get_impl_type();
- possible_params = impl.get_trait_params();
- best_impl = mv$(impl);
- count -= 1;
+ const auto& best_impl = possible_impl.impl_ref;
+ // TODO: Handle duplicates (from overlapping bounds)
+ if( impl.overlaps_with(context.m_crate, best_impl) )
+ {
+ DEBUG("[check_associated] - Overlaps with existing - " << best_impl);
+ // if not more specific than the existing best, ignore.
+ if( ! impl.more_specific_than(best_impl) )
+ {
+ DEBUG("[check_associated] - Less specific than existing");
+ // NOTE: This picks the _least_ specific impl
+ possible_impl.impl_ty = impl.get_impl_type();
+ possible_impl.params = impl.get_trait_params();
+ possible_impl.impl_ref = mv$(impl);
+ count -= 1;
+ }
+ // If the existing best is not more specific than the new one, use the new one
+ else if( ! best_impl.more_specific_than(impl) )
+ {
+ DEBUG("[check_associated] - More specific than existing - " << best_impl);
+ count -= 1;
+ }
+ else
+ {
+ // Supposedly, `more_specific_than` should be reflexive...
+ DEBUG("[check_associated] > Neither is more specific. Error?");
+ }
+ was_used = true;
+ break;
+ }
+ else
+ {
+ // Disjoint impls.
+ DEBUG("[check_associated] Disjoint with " << best_impl);
+ }
}
- // If the existing best is not more specific than the new one, use the new one
- else if( ! best_impl.more_specific_than(impl) )
+ if( !was_used )
{
- DEBUG("[check_associated] - More specific than existing - " << impl);
- count -= 1;
+ DEBUG("[check_associated] Add new possible impl " << impl);
+ possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) });
}
- else
- {
- // Supposedly, `more_specific_than` should be reflexive...
- DEBUG("[check_associated] > Neither is more specific. Error?");
- }
- }
- else
- {
- // Disjoint impls.
- DEBUG("[check_associated] Disjoint impl -" << impl);
}
- #endif
return false;
}
@@ -5328,12 +6825,17 @@ namespace {
}
context.equate_types(sp, v.left_ty, output_type);
}
+ // TODO: Any equating of type params?
return true;
}
else if( count == 0 ) {
// No applicable impl
// - TODO: This should really only fire when there isn't an impl. But it currently fires when _
- DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ if( v.name == "" )
+ DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ else
+ DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)
+ << " with " << v.name << " = " << context.m_ivars.fmt_type(v.left_ty));
const auto& ty = context.get_type(v.impl_ty);
bool is_known = !ty.m_data.is_Infer() && !(ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound());
@@ -5366,6 +6868,9 @@ namespace {
}
}
else if( count == 1 ) {
+ auto& possible_impl_ty = possible_impls.at(0).impl_ty;
+ auto& possible_params = possible_impls.at(0).params;
+ auto& best_impl = possible_impls.at(0).impl_ref;
DEBUG("Only one impl " << v.trait << context.m_ivars.fmt(possible_params) << " for " << context.m_ivars.fmt_type(possible_impl_ty)
<< " - out=" << output_type);
// - If there are any magic params in the impl, don't use it yet.
@@ -5385,6 +6890,7 @@ namespace {
if( TU_TEST1(impl_ty.m_data, Infer, .is_lit() == false) )
{
DEBUG("Unbounded ivar, waiting - TODO: Add possibility " << impl_ty << " == " << possible_impl_ty);
+ //context.possible_equate_type_bound(sp, impl_ty.m_data.as_Infer().index, possible_impl_ty);
return false;
}
// Only one possible impl
@@ -5440,636 +6946,1430 @@ namespace {
else {
// Multiple possible impls, don't know yet
DEBUG("Multiple impls");
+ for(const auto& pi : possible_impls)
+ {
+ DEBUG(pi.params << " for " << pi.impl_ty);
+ for(size_t i = 0; i < pi.params.m_types.size(); i++)
+ {
+ const auto& t = context.get_type(v.params.m_types[i]);
+ if( const auto* e = t.m_data.opt_Infer() ) {
+ const auto& pi_t = pi.params.m_types[i];
+ if( !type_contains_impl_placeholder(pi_t) )
+ {
+ context.possible_equate_type_bound(sp, e->index, pi_t);
+ }
+ else
+ {
+ DEBUG("Not adding placeholder-containing type as a bound - " << pi_t);
+ }
+ }
+ }
+ }
return false;
}
}
- bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true)
+ bool check_ivar_poss__fails_bounds(const Span& sp, Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& new_ty)
+ {
+ for(const auto& bound : context.link_assoc)
+ {
+ bool used_ty = false;
+ auto cb = [&](const ::HIR::TypeRef& ty, ::HIR::TypeRef& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }};
+ auto t = clone_ty_with(sp, bound.impl_ty, cb);
+ auto p = clone_path_params_with(sp, bound.params, cb);
+ if(!used_ty)
+ continue;
+ // - Run EAT on t and p
+ t = context.m_resolve.expand_associated_types( sp, mv$(t) );
+ // TODO: EAT on `p`
+ DEBUG("Check " << t << " : " << bound.trait << p);
+ DEBUG("- From " << bound.impl_ty << " : " << bound.trait << bound.params);
+
+ // Search for any trait impl that could match this,
+ bool bound_failed = true;
+ context.m_resolve.find_trait_impls(sp, bound.trait, p, t, [&](const auto impl, auto cmp){
+ // If this bound specifies an associated type, then check that that type could match
+ if( bound.name != "" )
+ {
+ auto aty = impl.get_type(bound.name.c_str());
+ // The associated type is not present, what does that mean?
+ if( aty == ::HIR::TypeRef() ) {
+ DEBUG("[check_ivar_poss__fails_bounds] No ATY for " << bound.name << " in impl");
+ // A possible match was found, so don't delete just yet
+ bound_failed = false;
+ // - Return false to keep searching
+ return false;
+ }
+ else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) {
+ DEBUG("[check_ivar_poss__fails_bounds] ATY " << context.m_ivars.fmt_type(aty) << " != left " << context.m_ivars.fmt_type(bound.left_ty));
+ bound_failed = true;
+ // - Bail instantly
+ return true;
+ }
+ else {
+ }
+ }
+ bound_failed = false;
+ return true;
+ });
+ if( bound_failed && ! t.m_data.is_Infer() ) {
+ // If none was found, remove from the possibility list
+ DEBUG("Remove possibility " << new_ty << " because it failed a bound");
+ return true;
+ }
+
+ // TODO: Check for the resultant associated type
+ }
+
+ // Handle methods
+ for(const auto* node_ptr_dyn : context.to_visit)
+ {
+ if( const auto* node_ptr = dynamic_cast<const ::HIR::ExprNode_CallMethod*>(node_ptr_dyn) )
+ {
+ const auto& node = *node_ptr;
+ const auto& ty_tpl = context.get_type(node.m_value->m_res_type);
+
+ bool used_ty = false;
+ auto t = clone_ty_with(sp, ty_tpl, [&](const auto& ty, auto& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }});
+ if(!used_ty)
+ continue;
+
+ DEBUG("Check <" << t << ">::" << node.m_method);
+ ::std::vector<::std::pair<TraitResolution::AutoderefBorrow, ::HIR::Path>> possible_methods;
+ unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method.c_str(), possible_methods);
+ DEBUG("> deref_count = " << deref_count << ", " << possible_methods);
+ if( !t.m_data.is_Infer() && possible_methods.empty() )
+ {
+ // No method found, which would be an error
+ return true;
+ }
+ }
+ else
+ {
+ }
+ }
+
+ return false;
+ }
+
+ enum class IvarPossFallbackType {
+ None, // No fallback, only make safe decisions
+ Assume, // Picks an option, even if there's non source/destination types
+ IgnoreWeakDisable, // Ignores the weaker disable flags
+ FinalOption,
+ };
+ ::std::ostream& operator<<(::std::ostream& os, IvarPossFallbackType t) {
+ switch(t)
+ {
+ case IvarPossFallbackType::None: os << ""; break;
+ case IvarPossFallbackType::Assume: os << " weak"; break;
+ case IvarPossFallbackType::IgnoreWeakDisable: os << " unblock"; break;
+ case IvarPossFallbackType::FinalOption: os << " final"; break;
+ }
+ return os;
+ }
+ /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls
+ bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, IvarPossFallbackType fallback_ty=IvarPossFallbackType::None)
{
static Span _span;
const auto& sp = _span;
+ const bool honour_disable = (fallback_ty != IvarPossFallbackType::IgnoreWeakDisable);
- if( ! ivar_ent.has_rules() ) {
- // No rules, don't do anything (and don't print)
- DEBUG(i << ": No rules");
+ if( ivar_ent.force_disable )
+ {
+ DEBUG(i << ": forced unknown");
return false;
}
+ if( ivar_ent.force_no_to || ivar_ent.force_no_from )
+ {
+ switch(fallback_ty)
+ {
+ case IvarPossFallbackType::IgnoreWeakDisable:
+ case IvarPossFallbackType::FinalOption:
+ break;
+ default:
+ DEBUG(i << ": coercion blocked");
+ return false;
+ }
+ }
::HIR::TypeRef ty_l_ivar;
ty_l_ivar.m_data.as_Infer().index = i;
const auto& ty_l = context.m_ivars.get_type(ty_l_ivar);
- bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false);
if( ty_l != ty_l_ivar ) {
- DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l);
- // Completely clear by reinitialising
- ivar_ent = Context::IVarPossible();
+ if( ivar_ent.has_rules() )
+ {
+ DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l);
+ // Completely clear by reinitialising
+ ivar_ent = Context::IVarPossible();
+ }
+ else
+ {
+ //DEBUG(i << ": known " << ty_l);
+ }
return false;
}
- enum class DedupKeep {
- Both,
- Left,
- Right,
- };
- struct H {
- static void dedup_type_list_with(::std::vector< ::HIR::TypeRef>& list, ::std::function<DedupKeep(const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)> cmp) {
- if( list.size() <= 1 )
- return ;
+ // Don't attempt to guess literals
+ // - What about if they're bounded?
+ if( ty_l.m_data.as_Infer().is_lit() )
+ {
+ DEBUG(i << ": Literal " << ty_l);
+ return false;
+ }
+ if( ! ivar_ent.has_rules() )
+ {
+ if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge )
+ {
+ DEBUG("Set IVar " << i << " = ! (no rules, and is diverge-class ivar)");
+ context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge();
+ context.m_ivars.mark_change();
+ return true;
+ }
+ // No rules, don't do anything (and don't print)
+ DEBUG(i << ": No rules");
+ return false;
+ }
+
+ TRACE_FUNCTION_F(i << fallback_ty << " - " << ty_l);
+
- for( auto it = list.begin(); it != list.end(); )
+ bool has_no_coerce_posiblities;
+
+ // Fill a single list with all possibilities, and pick the most suitable type.
+ // - This list needs to include flags to say if the type can be dereferenced.
+ {
+ // TODO: Move this to its own function.
+ struct PossibleType {
+ bool is_pointer; // I.e. it's from a coerce
+ bool can_deref; // I.e. from an unsize or coerce, AND it's a "from"
+ const ::HIR::TypeRef* ty;
+
+ bool operator<(const PossibleType& o) const {
+ if( *ty != *o.ty )
+ return *ty < *o.ty;
+ if( is_pointer != o.is_pointer )
+ return is_pointer < o.is_pointer;
+ if( can_deref < o.can_deref )
+ return can_deref < o.can_deref;
+ return false;
+ }
+ ::std::ostream& fmt(::std::ostream& os) const {
+ return os << (is_pointer ? "C" : "-") << (can_deref ? "D" : "-") << " " << *ty;
+ }
+
+ bool is_source() const { return this->can_deref; }
+ bool is_dest() const { return !this->can_deref; }
+ static bool is_source_s(const PossibleType& self) { return self.is_source(); }
+ static bool is_dest_s(const PossibleType& self) { return self.is_dest(); }
+ };
+
+ bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false);
+
+ ::std::vector<PossibleType> possible_tys;
+ static ::HIR::TypeRef null_placeholder;
+ bool add_placeholders = (fallback_ty < IvarPossFallbackType::IgnoreWeakDisable);
+ if( add_placeholders && ivar_ent.force_no_from ) // TODO: This can't happen, there's an early return above.
+ {
+ possible_tys.push_back(PossibleType { false, true, &null_placeholder });
+ }
+ for(const auto& new_ty : ivar_ent.types_coerce_from )
+ {
+ possible_tys.push_back(PossibleType { true , true, &new_ty });
+ }
+ for(const auto& new_ty : ivar_ent.types_unsize_from )
+ {
+ possible_tys.push_back(PossibleType { false, true, &new_ty });
+ }
+ if( add_placeholders && ivar_ent.force_no_to ) // TODO: This can't happen, there's an early return above.
+ {
+ possible_tys.push_back(PossibleType { false, false, &null_placeholder });
+ }
+ for(const auto& new_ty : ivar_ent.types_coerce_to )
+ {
+ possible_tys.push_back(PossibleType { true , false, &new_ty });
+ }
+ for(const auto& new_ty : ivar_ent.types_unsize_to )
+ {
+ possible_tys.push_back(PossibleType { false, false, &new_ty });
+ }
+ DEBUG("possible_tys = " << possible_tys);
+
+ // If exactly the same type is both a source and destination, equate.
+ // - This is always correct, even if one of the types is an ivar (you can't go A -> B -> A with a coercion)
+ {
+ for(const auto& ent : possible_tys)
{
- bool found = false;
- for( auto it2 = list.begin(); it2 != it; ++ it2 ) {
- auto action = cmp(*it, *it2);
- if( action != DedupKeep::Both )
- {
- if( action == DedupKeep::Right ) {
- //DEBUG("Keep " << *it << ", toss " << *it2);
- }
- else {
- ::std::swap(*it2, *it);
- //DEBUG("Keep " << *it << ", toss " << *it2 << " (swapped)");
- }
- found = true;
- break;
+ if( !ent.can_deref )
+ continue ;
+ for(const auto& ent2 : possible_tys)
+ {
+ if( &ent == &ent2 ) {
+ continue;
}
- }
- if( found ) {
- it = list.erase(it);
- }
- else {
- ++ it;
+ if( ent2.can_deref ) {
+ continue ;
+ }
+ if( *ent.ty != ::HIR::TypeRef() && *ent.ty == *ent2.ty ) {
+ DEBUG("- Source/Destination type");
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ // TODO: Compare such that &[_; 1] == &[u8; 1]?
}
}
}
- // De-duplicate list (taking into account other ivars)
- // - TODO: Use the direction and do a fuzzy equality based on coercion possibility
- static void dedup_type_list(const Context& context, ::std::vector< ::HIR::TypeRef>& list) {
- dedup_type_list_with(list, [&context](const auto& l, const auto& r){ return H::equal_to(context, l, r) ? DedupKeep::Left : DedupKeep::Both; });
+
+#if 1
+ if( ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_source_s) == 1 && !ivar_ent.force_no_from )
+ {
+ // Single source, pick it?
+ const auto& ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_source_s);
+ // - Only if there's no ivars
+ if( !context.m_ivars.type_contains_ivars(*ent.ty) )
+ {
+ if( !check_ivar_poss__fails_bounds(sp, context, ty_l, *ent.ty) )
+ {
+ DEBUG("Single concrete source, " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ }
}
+#endif
- // Types are equal from the view of being coercion targets
- // - Inequality here means that the targets could coexist in the list (e.g. &[u8; N] and &[u8])
- // - Equality means that they HAVE to be equal (even if they're not currently due to ivars)
- // - E.g. &mut HashMap<_1> and &mut HashMap<T> would unify
- static bool equal_to(const Context& context, const ::HIR::TypeRef& ia, const ::HIR::TypeRef& ib) {
- const auto& a = context.m_ivars.get_type(ia);
- const auto& b = context.m_ivars.get_type(ib);
- if( a.m_data.tag() != b.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::TypeRef::Data, (a.m_data, b.m_data), (e_a, e_b),
- (
- return context.m_ivars.types_equal(a, b);
- ),
- (Borrow,
- if( e_a.type != e_b.type )
- return false;
- const auto& ia = context.m_ivars.get_type(*e_a.inner);
- const auto& ib = context.m_ivars.get_type(*e_b.inner);
- if( ia.m_data.tag() != ib.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ia.m_data, ib.m_data), (e_ia, e_ib),
- (
- return context.m_ivars.types_equal(ia, ib);
- ),
- (Infer,
- return false;
- ),
- (Path,
- if( e_ia.binding.tag() != e_ib.binding.tag() )
- return false;
- TU_MATCHA( (e_ia.binding, e_ib.binding), (pbe_a, pbe_b),
- (Unbound, return false; ),
- (Opaque,
- // TODO: Check bounds?
- return false;
- ),
- (Struct,
- if(pbe_a != pbe_b) return false;
- if( !pbe_a->m_struct_markings.can_unsize )
- return true;
- // It _could_ unsize, so let it coexist
- return false;
- ),
- (Union,
- return false;
- ),
- (Enum,
- return false;
- )
- )
- ),
- (Slice,
- const auto& ia2 = context.m_ivars.get_type(*e_ia.inner);
- const auto& ib2 = context.m_ivars.get_type(*e_ib.inner);
- if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer())
- return true;
- return context.m_ivars.types_equal(ia2, ib2);
- )
- )
- ),
- (Pointer,
- if( e_a.type != e_b.type )
- return false;
- // TODO: Rules are subtly different when coercing from a pointer?
- const auto& ia2 = context.m_ivars.get_type(*e_a.inner);
- const auto& ib2 = context.m_ivars.get_type(*e_b.inner);
- if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer())
+
+ if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge )
+ {
+ // There's a coercion (not an unsizing) AND there's no sources
+ // - This ensures that the ! is directly as a value, and not as a generic param or behind a pointer
+ if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.is_pointer; })
+ && ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.can_deref; })
+ )
+ {
+ if( !ivar_ent.force_no_to && ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s) == 1 )
+ {
+ auto ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s);
+ DEBUG("One destination (diverge, no source), setting to " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
return true;
- return context.m_ivars.types_equal(ia2, ib2);
- )
- )
- //
- return context.m_ivars.types_equal(a, b);
+ }
+
+ // There are no source possibilities, this has to be a `!`
+ DEBUG("- Diverge with no source types, force setting to !");
+ DEBUG("Set IVar " << i << " = !");
+ context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge();
+ context.m_ivars.mark_change();
+ return true;
+ }
}
- // Types are equal from the view of being coercion sources
- static bool equal_from(const Context& context, const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) {
- return context.m_ivars.types_equal(a, b);
+
+ // If there's no disable flags set, and there's only one source, pick it.
+ // - Slight hack to speed up flow-down inference
+ if( possible_tys.size() == 1 && possible_tys[0].can_deref && !ivar_ent.force_no_from ) {
+ DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty);
+ context.equate_types(sp, ty_l, *possible_tys[0].ty);
+ return true;
}
+ //if( possible_tys.size() == 1 && !possible_tys[0].can_deref && !ivar_ent.force_no_to ) {
+ // DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty);
+ // context.equate_types(sp, ty_l, *possible_tys[0].ty);
+ // return true;
+ //}
- // TODO: `can_unsize_to`
- static bool can_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) {
- if( dst.m_data.is_Infer() )
- return false;
- if( src.m_data.is_Infer() )
+ // TODO: This shouldn't just return, instead the above null placeholders should be tested
+ if( ivar_ent.force_no_to || ivar_ent.force_no_from )
+ {
+ switch(fallback_ty)
+ {
+ case IvarPossFallbackType::IgnoreWeakDisable:
+ case IvarPossFallbackType::FinalOption:
+ break;
+ default:
+ DEBUG(i << ": coercion blocked");
return false;
+ }
+ }
- if( dst.m_data.is_Borrow() && src.m_data.is_Borrow() ) {
- const auto& d_e = dst.m_data.as_Borrow();
- const auto& s_e = src.m_data.as_Borrow();
+ // TODO: Single destination, and all sources are coerce-able
+ // - Pick the single destination
+ #if 0
+ if( !ivar_ent.force_no_to && ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s) == 1 )
+ {
+ auto ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s);
+ DEBUG("One destination, setting to " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ #endif
- // Higher = more specific (e.g. Unique > Shared)
- if( s_e.type < d_e.type ) {
- return false;
+ // Filter out ivars
+ // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes)
+ size_t n_ivars;
+ size_t n_src_ivars;
+ size_t n_dst_ivars;
+ {
+ n_src_ivars = 0;
+ n_dst_ivars = 0;
+ auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [&](const PossibleType& ent) {
+ // TODO: Should this remove Unbound associated types too?
+ if( ent.ty->m_data.is_Infer() )
+ {
+ if( ent.can_deref )
+ {
+ n_src_ivars += 1;
+ }
+ else
+ {
+ n_dst_ivars += 1;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ });
+ n_ivars = possible_tys.end() - new_end;
+ possible_tys.erase(new_end, possible_tys.end());
+ }
+ DEBUG(n_ivars << " ivars (" << n_src_ivars << " src, " << n_dst_ivars << " dst)");
+ (void)n_ivars;
+
+ // === If there's no source ivars, find the least permissive source ===
+ // - If this source can't be unsized (e.g. in `&_, &str`, `&str` is the least permissive, and can't be
+ // coerced without a `*const _` in the list), then equate to that
+ // 1. Find the most accepting pointer type (if there is at least one coercion source)
+ // 2. Look for an option that uses that pointer type, and contains an unsized type (that isn't a trait
+ // object with markers)
+ // 3. Assign to that known most-permissive option
+ // TODO: Do the oposite for the destination types (least permissive pointer, pick any Sized type)
+ if( n_src_ivars == 0 || fallback_ty == IvarPossFallbackType::Assume )
+ {
+ static const ::HIR::TypeRef::Data::Tag tag_ordering[] = {
+ //::HIR::TypeRef::Data::TAG_Generic,
+ ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic?
+ ::HIR::TypeRef::Data::TAG_Borrow,
+ ::HIR::TypeRef::Data::TAG_Pointer,
+ };
+ struct H {
+ static Ordering ord_accepting_ptr(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r)
+ {
+ // Ordering in increasing acceptiveness:
+ // - Paths, Borrows, Raw Pointers
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() )
+ {
+ const auto* tag_ordering_end = tag_ordering+sizeof(tag_ordering)/sizeof(tag_ordering[0]);
+ auto it_l = ::std::find(tag_ordering, tag_ordering_end, ty_l.m_data.tag());
+ auto it_r = ::std::find(tag_ordering, tag_ordering_end, ty_r.m_data.tag());
+ if( it_l == tag_ordering_end || it_r == tag_ordering_end ) {
+ // Huh?
+ return OrdEqual;
+ }
+ if( it_l < it_r )
+ return OrdLess;
+ else if( it_l > it_r )
+ return OrdGreater;
+ else
+ throw "Impossible";
+ }
+
+ switch(ty_l.m_data.tag())
+ {
+ case ::HIR::TypeRef::Data::TAG_Borrow:
+ // Reverse order - Shared is numerically lower than Unique, but is MORE accepting
+ return ::ord( static_cast<int>(ty_r.m_data.as_Borrow().type), static_cast<int>(ty_l.m_data.as_Borrow().type) );
+ case ::HIR::TypeRef::Data::TAG_Pointer:
+ // Reverse order - Shared is numerically lower than Unique, but is MORE accepting
+ return ::ord( static_cast<int>(ty_r.m_data.as_Pointer().type), static_cast<int>(ty_l.m_data.as_Pointer().type) );
+ case ::HIR::TypeRef::Data::TAG_Path:
+ return OrdEqual;
+ case ::HIR::TypeRef::Data::TAG_Generic:
+ return OrdEqual;
+ default:
+ // Technically a bug/error
+ return OrdEqual;
+ }
}
- else if( s_e.type == d_e.type ) {
- // Check relationship
- // - 1. Deref chain.
- // - 2. Trait object?
+
+ static const ::HIR::TypeRef* match_and_extract_ptr_ty(const ::HIR::TypeRef& ptr_tpl, const ::HIR::TypeRef& ty)
+ {
+ if( ty.m_data.tag() != ptr_tpl.m_data.tag() )
+ return nullptr;
+ TU_MATCH_HDRA( (ty.m_data), { )
+ TU_ARMA(Borrow, te) {
+ if( te.type == ptr_tpl.m_data.as_Borrow().type ) {
+ return &*te.inner;
+ }
+ }
+ TU_ARMA(Pointer, te) {
+ if( te.type == ptr_tpl.m_data.as_Pointer().type ) {
+ return &*te.inner;
+ }
+ }
+ TU_ARMA(Path, te) {
+ if( te.binding == ptr_tpl.m_data.as_Path().binding ) {
+ // TODO: Get inner
+ }
+ } break;
+ default:
+ break;
+ }
+ return nullptr;
}
- else {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ };
+ const ::HIR::TypeRef* ptr_ty = nullptr;
+ if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [&](const auto& ent){ return ent.can_deref && ent.is_pointer; }) )
+ {
+ for(const auto& ent : possible_tys)
+ {
+ if( !ent.can_deref )
+ continue;
+
+ if( ptr_ty == nullptr )
+ {
+ ptr_ty = ent.ty;
+ }
+ else if( H::ord_accepting_ptr(*ent.ty, *ptr_ty) == OrdGreater )
+ {
+ ptr_ty = ent.ty;
+ }
+ else
+ {
+ }
}
}
- if( dst.m_data.is_Pointer() && src.m_data.is_Pointer() ) {
- const auto& d_e = dst.m_data.as_Pointer();
- const auto& s_e = src.m_data.as_Pointer();
- // Higher = more specific (e.g. Unique > Shared)
- if( s_e.type < d_e.type ) {
- return false;
+ for(const auto& ent : possible_tys)
+ {
+ // Sources only
+ if( ! ent.can_deref )
+ continue ;
+ // Must match `ptr_ty`'s outer pointer
+ const ::HIR::TypeRef* inner_ty = (ptr_ty ? H::match_and_extract_ptr_ty(*ptr_ty, *ent.ty) : ent.ty);
+ if( !inner_ty )
+ continue;
+
+ bool is_max_accepting = false;
+ if( inner_ty->m_data.is_Slice() ) {
+ is_max_accepting = true;
}
- else if( s_e.type == d_e.type ) {
- // Check relationship
- // - 1. Deref chain.
- // - 2. Trait object?
+ else if( TU_TEST1(inner_ty->m_data, Primitive, == ::HIR::CoreType::Str) ) {
+ is_max_accepting = true;
}
else {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ }
+ if( is_max_accepting )
+ {
+ DEBUG("Most accepting pointer class, and most permissive inner type - " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
}
}
+ }
- if( dst.m_data.is_Pointer() && src.m_data.is_Borrow() ) {
- const auto& d_e = dst.m_data.as_Pointer();
- const auto& s_e = src.m_data.as_Borrow();
- if( s_e.type == d_e.type ) {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ struct TypeRestrictiveOrdering {
+ static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r)
+ {
+ // For infer, only concrete types are more restrictive
+ TU_MATCH_HDRA( (r.m_data), { )
+ default:
+ return OrdLess;
+ TU_ARMA(Path, te) {
+ if( te.binding.is_Opaque() )
+ return OrdLess;
+ if( te.binding.is_Unbound() )
+ return OrdEqual;
+ // TODO: Check if the type is concrete? (Check an unsizing param if present)
+ return OrdLess;
+ }
+ TU_ARMA(Borrow, _)
+ return OrdEqual;
+ TU_ARMA(Infer, _)
+ return OrdEqual;
+ TU_ARMA(Pointer, _)
+ return OrdEqual;
}
+ throw "";
}
- return false;
- }
+ // Ordering of `l` relative to `r`, OrdLess means that the LHS is less restrictive
+ static Ordering get_ordering_ty(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)
+ {
+ if( l == r ) {
+ return OrdEqual;
+ }
+ if( l.m_data.is_Infer() ) {
+ return get_ordering_infer(sp, r);
+ }
+ if( r.m_data.is_Infer() ) {
+ switch( get_ordering_infer(sp, l) )
+ {
+ case OrdLess: return OrdGreater;
+ case OrdEqual: return OrdEqual;
+ case OrdGreater:return OrdLess;
+ }
+ }
+ if( l.m_data.is_Path() ) {
+ const auto& te_l = l.m_data.as_Path();
+ // Path types can be unsize targets, and can also act like infers
+ // - If it's a Unbound treat as Infer
+ // - If Opaque, then search for a CoerceUnsized/Unsize bound?
+ // - If Struct, look for ^ tag
+ // - Else, more/equal specific
+ TU_MATCH_HDRA( (r.m_data), { )
+ default:
+ // An ivar is less restrictive?
+ if( te_l.binding.is_Unbound() )
+ return OrdLess;
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is ?");
+ TU_ARMA(Path, te_r) {
+ if( te_l.binding.is_Unbound() && te_r.binding.is_Unbound() )
+ {
+ return OrdEqual;
+ }
+ if( te_l.binding.is_Unbound() )
+ return OrdLess;
+ if( te_r.binding.is_Unbound() )
+ {
+ return OrdGreater;
+ }
+ else if( te_r.binding.is_Opaque() )
+ {
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is opaque type");
+ }
+ else if( TU_TEST1(te_r.binding, Struct, ->m_struct_markings.can_unsize) )
+ {
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is unsize-capable struct");
+ }
+ else
+ {
+ return OrdEqual;
+ }
+ }
+ }
+ }
+ if( r.m_data.is_Path() ) {
+ // Path types can be unsize targets, and can also act like infers
+ switch( get_ordering_ty(sp, context, r, l) )
+ {
+ case OrdLess: return OrdGreater;
+ case OrdEqual: return OrdEqual;
+ case OrdGreater:return OrdLess;
+ }
+ }
- // Returns true if the `src` concretely cannot coerce to `dst`
- static bool cannot_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) {
- TU_IFLET( ::HIR::TypeRef::Data, src.m_data, Borrow, se,
- TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Borrow, de,
- )
- else TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Pointer, de,
- )
+ // Slice < Array
+ if( l.m_data.tag() == r.m_data.tag() ) {
+ return OrdEqual;
+ }
else {
- return true;
+ if( l.m_data.is_Slice() && r.m_data.is_Array() ) {
+ return OrdGreater;
+ }
+ if( l.m_data.is_Array() && r.m_data.is_Slice() ) {
+ return OrdLess;
+ }
+ TODO(sp, "Compare " << l << " and " << r);
}
+ }
+
+ // Returns the restrictiveness ordering of `l` relative to `r`
+ // - &T is more restrictive than *const T
+ // - &mut T is more restrictive than &T
+ // Restrictive means that left can't be coerced from right
+ static Ordering get_ordering_ptr(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)
+ {
+ Ordering cmp;
+ TRACE_FUNCTION_FR(l << " , " << r, cmp);
+ // Get ordering of this type to the current destination
+ // - If lesser/greater then ignore/update
+ // - If equal then what? (Instant error? Leave as-is and let the asignment happen? Disable the asignment?)
+ static const ::HIR::TypeRef::Data::Tag tag_ordering[] = {
+ ::HIR::TypeRef::Data::TAG_Pointer,
+ ::HIR::TypeRef::Data::TAG_Borrow,
+ ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic
+ ::HIR::TypeRef::Data::TAG_Generic,
+ };
+ static const ::HIR::TypeRef::Data::Tag* tag_ordering_end = &tag_ordering[ sizeof(tag_ordering) / sizeof(tag_ordering[0] )];
+ if( l.m_data.tag() != r.m_data.tag() )
+ {
+ auto p_l = ::std::find(tag_ordering, tag_ordering_end, l.m_data.tag());
+ auto p_r = ::std::find(tag_ordering, tag_ordering_end, r.m_data.tag());
+ if( p_l == tag_ordering_end ) {
+ TODO(sp, "Type " << l << " not in ordering list");
+ }
+ if( p_r == tag_ordering_end ) {
+ TODO(sp, "Type " << r << " not in ordering list");
+ }
+ cmp = ord( static_cast<int>(p_l-p_r), 0 );
+ }
+ else
+ {
+ TU_MATCH_HDRA( (l.m_data), { )
+ default:
+ BUG(sp, "Unexpected type class " << l << " in get_ordering_ty");
+ break;
+ TU_ARMA(Generic, _te_l) {
+ cmp = OrdEqual;
+ }
+ TU_ARMA(Path, te_l) {
+ //const auto& te = dest_type->m_data.as_Path();
+ // TODO: Prevent this rule from applying?
+ return OrdEqual;
+ }
+ TU_ARMA(Borrow, te_l) {
+ const auto& te_r = r.m_data.as_Borrow();
+ cmp = ord( (int)te_l.type, (int)te_r.type ); // Unique>Shared in the listing, and Unique is more restrictive than Shared
+ if( cmp == OrdEqual )
+ {
+ cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner));
+ }
+ }
+ TU_ARMA(Pointer, te_l) {
+ const auto& te_r = r.m_data.as_Pointer();
+ cmp = ord( (int)te_r.type, (int)te_l.type ); // Note, reversed ordering because we want Unique>Shared
+ if( cmp == OrdEqual )
+ {
+ cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner));
+ }
+ }
+ }
+ }
+ return cmp;
+ }
+ };
+
+ // If there's multiple source types (which means that this ivar has to be a coercion from one of them)
+ // Look for the least permissive of the available destination types and assign to that
+ #if 1
+ // NOTE: This only works for coercions (not usizings), so is restricted to all options being pointers
+ if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; })
+ //|| ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; })
)
- return false;
+ {
+ // 1. Count distinct (and non-ivar) source types
+ // - This also ignores &_ types
+ size_t num_distinct = 0;
+ for(const auto& ent : possible_tys)
+ {
+ if( !ent.can_deref )
+ continue ;
+ // Ignore infer borrows
+ if( TU_TEST1(ent.ty->m_data, Borrow, .inner->m_data.is_Infer()) )
+ continue;
+ bool is_duplicate = false;
+ for(const auto& ent2 : possible_tys)
+ {
+ if( &ent2 == &ent )
+ break;
+ if( !ent.can_deref )
+ continue ;
+ if( *ent.ty == *ent2.ty ) {
+ is_duplicate = true;
+ break;
+ }
+ // TODO: Compare such that &[_; 1] == &[u8; 1]?
+ }
+ if( !is_duplicate )
+ {
+ num_distinct += 1;
+ }
+ }
+ DEBUG("- " << num_distinct << " distinct possibilities");
+ // 2. Find the most restrictive destination type
+ // - Borrows are more restrictive than pointers
+ // - Borrows of Sized types are more restrictive than any other
+ // - Decreasing borrow type ordering: Owned, Unique, Shared
+ const ::HIR::TypeRef* dest_type = nullptr;
+ for(const auto& ent : possible_tys)
+ {
+ if( ent.can_deref )
+ continue ;
+ // Ignore &_ types?
+ // - No, need to handle them below
+ if( !dest_type ) {
+ dest_type = ent.ty;
+ continue ;
+ }
+
+ auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type);
+ switch(cmp)
+ {
+ case OrdLess:
+ // This entry is less restrictive, so DO update `dest_type`
+ dest_type = ent.ty;
+ break;
+ case OrdEqual:
+ break;
+ case OrdGreater:
+ // This entry is more restrictive, so don't update `dest_type`
+ break;
+ }
+ }
+ // TODO: Unsized types? Don't pick an unsized if coercions are present?
+ // TODO: If in a fallback mode, then don't require >1 (just require dest_type)
+ if( (num_distinct > 1 || fallback_ty == IvarPossFallbackType::Assume) && dest_type )
+ {
+ DEBUG("- Most-restrictive destination " << *dest_type);
+ context.equate_types(sp, ty_l, *dest_type);
+ return true;
+ }
}
+ #endif
- static const ::HIR::TypeRef* find_lowest_type(const Context& context, const ::std::vector< ::HIR::TypeRef>& list)
+ // TODO: Remove any types that are covered by another type
+ // - E.g. &[T] and &[U] can be considered equal, because [T] can't unsize again
+ // - Comparison function: Returns one of Incomparible,Less,Same,More - Representing the amount of type information present.
{
- // 1. Locate types that cannot coerce to anything
- // - &TraitObject and &[T] are the main pair
- for(const auto& ty : list) {
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e,
- TU_MATCH_DEF(::HIR::TypeRef::Data, (e.inner->m_data), (e2),
+ struct InfoOrdering
+ {
+ enum Ordering {
+ Incompatible, // The types are incompatible
+ Less, // The LHS type provides less information (e.g. has more ivars)
+ Same, // Same number of ivars
+ More, // The RHS provides more information (less ivars)
+ };
+ static bool is_infer(const ::HIR::TypeRef& ty) {
+ if( ty.m_data.is_Infer() )
+ return true;
+ if( TU_TEST1(ty.m_data, Path, .binding.is_Unbound()) )
+ return true;
+ return false;
+ }
+ static Ordering compare(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) {
+ if( is_infer(ty_l) ) {
+ if( is_infer(ty_r) )
+ return Same;
+ return Less;
+ }
+ else {
+ if( is_infer(ty_r) )
+ return More;
+ }
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() ) {
+ return Incompatible;
+ }
+ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re),
(
+ return Incompatible;
),
- (Slice,
- return &ty;
+ (Tuple,
+ if( le.size() != re.size() )
+ return Incompatible;
+ int score = 0;
+ for(size_t i = 0; i < le.size(); i ++)
+ {
+ switch(compare(le[i], re[i]))
+ {
+ case Incompatible:
+ return Incompatible;
+ case Less: score --; break;
+ case Same: break;
+ case More: score ++; break;
+ }
+ }
+ if( score < 0 )
+ return Less;
+ else if( score > 0 )
+ return More;
+ else
+ return Same;
+ )
+ )
+ }
+ static Ordering compare_top(const Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r, bool should_deref) {
+ if( context.m_ivars.types_equal(ty_l, ty_r) )
+ return Same;
+ if( is_infer(ty_l) )
+ return Incompatible;
+ if( is_infer(ty_r) )
+ return Incompatible;
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() ) {
+ return Incompatible;
+ }
+ if( should_deref ) {
+ if( const auto* le = ty_l.m_data.opt_Borrow() ) {
+ const auto& re = ty_r.m_data.as_Borrow();
+ if( le->type != re.type )
+ return Incompatible;
+ return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false);
+ }
+ else if( const auto* le = ty_l.m_data.opt_Pointer() ) {
+ const auto& re = ty_r.m_data.as_Pointer();
+ if( le->type != re.type )
+ return Incompatible;
+ return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false);
+ }
+ else if( TU_TEST2(ty_l.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
+ {
+ const auto& le = ty_l.m_data.as_Path();
+ const auto& re = ty_l.m_data.as_Path();
+ if( le.binding != re.binding )
+ return Incompatible;
+ auto param_idx = le.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ return compare_top(context,
+ context.m_ivars.get_type(le.path.m_data.as_Generic().m_params.m_types.at(param_idx)),
+ context.m_ivars.get_type(re.path.m_data.as_Generic().m_params.m_types.at(param_idx)),
+ false
+ );
+ }
+ else
+ {
+ BUG(Span(), "Can't deref " << ty_l << " / " << ty_r);
+ }
+ }
+ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re),
+ (
+ return Incompatible;
),
- (TraitObject,
- return &ty;
+ (Slice,
+ switch(compare(context.m_ivars.get_type(*le.inner), context.m_ivars.get_type(*re.inner)))
+ {
+ case Less: return Less;
+ case More: return More;
+ case Same:
+ case Incompatible:
+ return Same;
+ }
+ throw "";
)
)
- )
- }
-
- // 2. Search the list for a type that is a valid coercion target for all other types in the list
- // - NOTE: Ivars return `false` nomatter what order
- const auto* cur_type = &list[0];
- for(const auto& ty : list) {
- // If ty can be coerced to the current type
- if( H::can_coerce_to(context, *cur_type, ty) ) {
- // - Keep current type
}
- else if( H::can_coerce_to(context, ty, *cur_type) ) {
- cur_type = &ty;
+ static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) {
+ const auto& t = context.m_ivars.get_type(t_raw);
+ if( const auto* te = t.m_data.opt_Borrow() ) {
+ return context.m_ivars.get_type(*te->inner);
+ }
+ else if( const auto* te = t.m_data.opt_Pointer() ) {
+ return context.m_ivars.get_type(*te->inner);
+ }
+ else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
+ {
+ const auto& te = t.m_data.as_Path();
+ auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ const auto& path = te.path.m_data.as_Generic();
+ return context.m_ivars.get_type(path.m_params.m_types.at(param_idx));
+ }
+ else {
+ throw "";
+ //return t;
+ }
}
- else {
- // Error? Give up.
- cur_type = nullptr;
- break;
+ };
+
+ // De-duplicate destinations and sources separately
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); ++it)
+ {
+ if( !it->ty )
+ continue;
+ for(auto it2 = it + 1; it2 != possible_tys.end(); ++it2)
+ {
+ if( !it2->ty )
+ continue;
+ if(it->can_deref != it2->can_deref) {
+ continue;
+ }
+ if(it->is_pointer != it2->is_pointer) {
+ continue;
+ }
+
+ switch(InfoOrdering::compare_top(context, *it->ty, *it2->ty, /*should_deref=*/it->is_pointer))
+ {
+ case InfoOrdering::Incompatible:
+ break;
+ case InfoOrdering::Less:
+ case InfoOrdering::Same:
+ DEBUG("Remove " << *it << ", keep " << *it2);
+ it->ty = it2->ty;
+ it->is_pointer = it2->is_pointer;
+ it2->ty = nullptr;
+ break;
+ case InfoOrdering::More:
+ DEBUG("Keep " << *it << ", remove " << *it2);
+ it2->ty = nullptr;
+ break;
+ }
}
}
- if( cur_type ) {
- // TODO: Replace
- //return cur_type;
- }
-
- return nullptr;
+ auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const auto& e){ return e.ty == nullptr; });
+ DEBUG("Removing " << (possible_tys.end() - new_end) << " redundant possibilities");
+ possible_tys.erase(new_end, possible_tys.end());
}
- /// Returns true if `dst` is found when dereferencing `src`
- static bool type_derefs_from(const Span& sp, const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src)
+ // TODO: If in fallback mode, pick the most permissive option
+ // - E.g. If the options are &mut T and *const T, use the *const T
+ if( fallback_ty == IvarPossFallbackType::Assume )
{
- ::HIR::TypeRef tmp;
- const ::HIR::TypeRef* ty = &src;
- do
+ // All are coercions (not unsizings)
+ if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) && n_ivars == 0 )
{
- if( context.m_ivars.types_equal(*ty, dst) )
+ // Find the least restrictive destination, and most restrictive source
+ const ::HIR::TypeRef* dest_type = nullptr;
+ bool any_ivar_present = false;
+ for(const auto& ent : possible_tys)
+ {
+ if( visit_ty_with(*ent.ty, [](const ::HIR::TypeRef& t){ return t.m_data.is_Infer(); }) ) {
+ any_ivar_present = true;
+ }
+ if( !dest_type ) {
+ dest_type = ent.ty;
+ continue ;
+ }
+
+ auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type);
+ switch(cmp)
+ {
+ case OrdLess:
+ // This entry is less restrictive, so DO update `dest_type`
+ dest_type = ent.ty;
+ break;
+ case OrdEqual:
+ break;
+ case OrdGreater:
+ // This entry is more restrictive, so don't update `dest_type`
+ break;
+ }
+ }
+
+ if( dest_type && n_ivars == 0 && any_ivar_present == false )
+ {
+ DEBUG("Suitable option " << *dest_type << " from " << possible_tys);
+ context.equate_types(sp, ty_l, *dest_type);
return true;
- } while( (ty = context.m_resolve.autoderef(sp, *ty, tmp)) );
- return false;
+ }
+ }
}
- static ::std::vector<::HIR::TypeRef>& merge_lists(const Context& context, ::std::vector<::HIR::TypeRef>& list_a, ::std::vector<::HIR::TypeRef>& list_b, ::std::vector<::HIR::TypeRef>& out)
+ DEBUG("possible_tys = " << possible_tys);
+ DEBUG("- Bounded [" << ivar_ent.bounded << "]");
+#if 1
+ if( !possible_tys.empty() )
{
- if( list_a.size() == 0 )
- return list_b;
- else if( list_b.size() == 0 )
- return list_a;
- else {
- for(const auto& t : list_a) {
- out.push_back( t.clone() );
+ for(const auto& new_ty : ivar_ent.bounded)
+ {
+ bool failed_a_bound = false;
+ // Check if this bounded type _cannot_ work with any of the existing bounds
+ // - Don't add to the possiblity list if so
+ for(const auto& opt : possible_tys)
+ {
+ CoerceResult res;
+ if( opt.can_deref ) {
+ DEBUG(" > " << new_ty << " =? " << *opt.ty);
+ res = check_unsize_tys(context, sp, new_ty, *opt.ty, nullptr, false);
+ }
+ else {
+ // Destination type, this option must deref to it
+ DEBUG(" > " << *opt.ty << " =? " << new_ty);
+ res = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false);
+ }
+ DEBUG(" = " << res);
+ if( res == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
+ else if( res == CoerceResult::Unknown ) {
+ // Should this also be treated as a fail?
+ }
}
- for(const auto& t : list_b ) {
- out.push_back( t.clone() );
+ if( !failed_a_bound )
+ {
+ // TODO: Don't add ivars?
+ if( new_ty == ty_l )
+ {
+ }
+ else if( new_ty.m_data.is_Infer() )
+ {
+ n_ivars += 1;
+ }
+ else
+ {
+ possible_tys.push_back(PossibleType { false, false, &new_ty });
+ }
}
- H::dedup_type_list(context, out);
- return out;
}
}
- };
-
- // If this type has an infer class active, don't allw a non-primitive to coerce over it.
- if( ty_l.m_data.as_Infer().is_lit() )
- {
- DEBUG("Literal checks");
- // TODO: Actively search possibility list for the real type.
- for(const auto& ty : ivar_ent.types_coerce_to)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_unsize_to)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_coerce_from)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_unsize_from)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- return false;
- }
-
- if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) )
- {
- DEBUG("- IVar " << ty_l << " is forced unknown");
- return false;
- }
- else
- {
- TRACE_FUNCTION_F(i);
-
-
- // TODO: Dedup based on context?
- // - The dedup should probably be aware of the way the types are used (for coercions).
- H::dedup_type_list(context, ivar_ent.types_coerce_to);
- H::dedup_type_list(context, ivar_ent.types_unsize_to);
- H::dedup_type_list(context, ivar_ent.types_coerce_from);
- H::dedup_type_list(context, ivar_ent.types_unsize_from);
-
- #if 0
- // If there is a default type compatible with all possibilities, use that.
- if( ivar_ent.types_default.size() > 0 ) {
- // TODO: Should multiple options be valid?
- ASSERT_BUG(Span(), ivar_ent.types_def.size() == 1, "TODO: Multiple default types for an ivar - " << ivar_ent.types_def);
- }
- #endif
-
- if( ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0
- && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0
- )
+#endif
+ DEBUG("possible_tys = " << possible_tys);
+ // Filter out useless options and impossiblities
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- DEBUG("-- No known options for " << ty_l);
- return false;
- }
- DEBUG("-- " << ty_l << " FROM=Coerce:{" << ivar_ent.types_coerce_from << "} / Unsize:{" << ivar_ent.types_unsize_from << "},"
- << " TO=Coerce:{" << ivar_ent.types_coerce_to << "} / Unsize:{" << ivar_ent.types_unsize_to << "}");
-
- // Find an entry in the `types_unsize_from` list that all other entries can unsize to
- H::dedup_type_list_with(ivar_ent.types_unsize_from, [&](const auto& l, const auto& r) {
- if( l.m_data.is_Infer() || r.m_data.is_Infer() )
- return DedupKeep::Both;
-
- // Check for fuzzy equality of types, and keep only one
- // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce)
- // TODO: Use `check_unsize_tys` instead
- if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
+ bool remove_option = false;
+ if( *it->ty == ty_l )
{
- DEBUG("Possible match, keep left");
- return DedupKeep::Left;
+ remove_option = true;
}
-
- // &T and T
- TU_IFLET( ::HIR::TypeRef::Data, l.m_data, Borrow, le,
- TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
- )
- else {
- // if *le.inner == r, return DedupKeep::Right
- if( context.m_ivars.types_equal(*le.inner, r) )
- return DedupKeep::Right;
- }
- )
- else {
- TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
- // if *re.inner == l, return DedupKeep::Left
- if( context.m_ivars.types_equal(*re.inner, l) )
- return DedupKeep::Left;
- )
+ else if( !allow_unsized && context.m_resolve.type_is_sized(sp, *it->ty) == ::HIR::Compare::Unequal )
+ {
+ remove_option = true;
}
- return DedupKeep::Both;
- });
- // Find an entry in the `types_coerce_from` list that all other entries can coerce to
- H::dedup_type_list_with(ivar_ent.types_coerce_from, [&](const auto& l, const auto& r) {
- if( l.m_data.is_Infer() || r.m_data.is_Infer() )
- return DedupKeep::Both;
-
- // Check for fuzzy equality of types, and keep only one
- // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce)
- // TODO: Use `check_coerce_tys` instead
- if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
+ else
{
- DEBUG("Possible match, keep left");
- return DedupKeep::Left;
+ // Keep
}
- if( l.m_data.is_Borrow() )
+ // TODO: Ivars have been removed, this sort of check should be moved elsewhere.
+ if( !remove_option && ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Integer )
{
- const auto& le = l.m_data.as_Borrow();
- ASSERT_BUG(sp, r.m_data.is_Borrow() || r.m_data.is_Pointer(), "Coerce source for borrow isn't a borrow/pointert - " << r);
- const auto re_borrow_type = r.m_data.is_Borrow() ? r.m_data.as_Borrow().type : r.m_data.as_Pointer().type;
- const auto& re_inner = r.m_data.is_Borrow() ? r.m_data.as_Borrow().inner : r.m_data.as_Pointer().inner;
-
- if( le.type < re_borrow_type ) {
- return DedupKeep::Left;
+ if( const auto* te = it->ty->m_data.opt_Primitive() ) {
+ (void)te;
+ }
+ else if( const auto* te = it->ty->m_data.opt_Path() ) {
+ // If not Unbound, remove option
+ (void)te;
}
- else if( le.type > re_borrow_type ) {
- return DedupKeep::Right;
+ else if( const auto* te = it->ty->m_data.opt_Infer() ) {
+ (void)te;
}
else {
+ remove_option = true;
}
-
- // Dereference `*re.inner` until it isn't possible or it equals `*le.inner`
- // - Repeat going the other direction.
- if( H::type_derefs_from(sp, context, *le.inner, *re_inner) )
- return DedupKeep::Left;
- if( H::type_derefs_from(sp, context, *re_inner, *le.inner) )
- return DedupKeep::Right;
}
- return DedupKeep::Both;
- });
-
- // If there's one option for both desination types, and nothing for the source ...
- if( ivar_ent.types_coerce_to.size() == 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_from.empty() && ivar_ent.types_unsize_from.empty() )
- {
- // And the coercion can unsize to the unsize, pick the coercion (it's valid, the other way around isn't)
- // TODO: Use a `can_unsize_to` functon instead (that handles Unsize as well as Deref)
- if( H::type_derefs_from(sp, context, ivar_ent.types_unsize_to[0], ivar_ent.types_coerce_to[0]) )
- {
- const auto& new_ty = ivar_ent.types_coerce_to[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (unsize to)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
- }
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
}
- #if 0
- // If there's only one coerce and unsize from, ...
- if( ivar_ent.types_coerce_from.size() == 1 && ivar_ent.types_unsize_from.size() == 1 && ivar_ent.types_coerce_to.empty() && ivar_ent.types_unsize_to.empty() )
+ DEBUG("possible_tys = " << possible_tys);
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- // and if the coerce can unsize to the unsize target.
- if( H::can_coerce_to(context, ivar_ent.types_unsize_from[0], ivar_ent.types_coerce_from[0]) )
+ bool remove_option = false;
+ for(const auto& other_opt : possible_tys)
{
- const auto& new_ty = ivar_ent.types_coerce_from[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (coerce from)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
+ if( &other_opt == &*it )
+ continue ;
+ if( *other_opt.ty == *it->ty )
+ {
+ // Potential duplicate
+ // - If the flag set is the same, then it is a duplicate
+ if( other_opt.can_deref == it->can_deref && other_opt.is_pointer == it->is_pointer ) {
+ remove_option = true;
+ break;
+ }
+ // If not an ivar, AND both are either unsize/pointer AND the deref flags are different
+ // TODO: Ivars have been removed?
+ if( !it->ty->m_data.is_Infer() && other_opt.is_pointer == it->is_pointer && other_opt.can_deref != it->can_deref )
+ {
+ // TODO: Possible duplicate with a check above...
+ DEBUG("Source and destination possibility, picking " << *it->ty);
+ context.equate_types(sp, ty_l, *it->ty);
+ return true;
+ }
+ // - Otherwise, we want to keep the option which doesn't allow dereferencing (remove current
+ // if it's the deref option)
+ if( it->can_deref && other_opt.is_pointer == it->is_pointer ) {
+ remove_option = true;
+ break;
+ }
+ }
}
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
}
- #endif
-
- //
-
- // HACK: Merge into a single lists
- ::std::vector< ::HIR::TypeRef> types_from_o;
- auto& types_from = H::merge_lists(context, ivar_ent.types_coerce_from, ivar_ent.types_unsize_from, types_from_o);
- ::std::vector< ::HIR::TypeRef> types_to_o;
- auto& types_to = H::merge_lists(context, ivar_ent.types_coerce_to , ivar_ent.types_unsize_to , types_to_o );
- DEBUG(" " << ty_l << " FROM={" << types_from << "}, TO={" << types_to << "}");
-
- // TODO: If there is only a single option and it's from an Unsize, is it valid?
-
- // TODO: Loop both lists and if there's T<_{int}> and T<uN/iN> unify those.
-
- // Same type on both sides, pick it.
- if( types_from == types_to && types_from.size() == 1 ) {
- const auto& new_ty = types_from[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (only)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
- }
-
- // Eliminate possibilities that don't fit known constraints
- if( types_to.size() > 0 && types_from.size() > 0 )
+ DEBUG("possible_tys = " << possible_tys);
+ // Remove any options that are filled by other options (e.g. `str` and a derferencable String)
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- // TODO: Search `types_to` too
- for(auto it = types_from.begin(); it != types_from.end(); )
+ bool remove_option = false;
+ if( it->can_deref && !it->ty->m_data.is_Infer() )
{
- bool remove = false;
- const auto& new_ty = context.get_type(*it);
- if( !new_ty.m_data.is_Infer() )
+ DEBUG("> " << *it);
+ // Dereference once before starting the search
+ ::HIR::TypeRef tmp, tmp2;
+ const auto* dty = it->ty;
+ auto src_bty = ::HIR::BorrowType::Shared;
+ if(it->is_pointer)
+ {
+ if( dty->m_data.is_Borrow() )
+ src_bty = dty->m_data.as_Borrow().type;
+ dty = context.m_resolve.autoderef(sp, *dty, tmp);
+ // NOTE: Coercions can also do closure->fn, so deref isn't always possible
+ //ASSERT_BUG(sp, dty, "Pointer (coercion source) that can't dereference - " << *it->ty);
+ }
+ //while( dty && !remove_option && (dty = context.m_resolve.autoderef(sp, *dty, tmp)) )
+ if( dty )
{
- for(const auto& bound : context.link_assoc)
+ for(const auto& other_opt : possible_tys)
{
- if( bound.impl_ty != ty_l )
+ if( &other_opt == &*it )
continue ;
+ if( other_opt.ty->m_data.is_Infer() )
+ continue ;
+ DEBUG(" > " << other_opt);
- // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement?
-
- // Search for any trait impl that could match this,
- bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;});
- if( !has ) {
- // If none was found, remove from the possibility list
- remove = true;
- DEBUG("Remove possibility " << new_ty << " because it failed a bound");
- break ;
+ const auto* oty = other_opt.ty;
+ auto o_bty = ::HIR::BorrowType::Owned;
+ if(other_opt.is_pointer)
+ {
+ if( oty->m_data.is_Borrow() )
+ o_bty = oty->m_data.as_Borrow().type;
+ oty = context.m_resolve.autoderef(sp, *oty, tmp2);
+ //ASSERT_BUG(sp, oty, "Pointer (coercion src/dst) that can't dereference - " << *other_opt.ty);
+ }
+ if( o_bty > src_bty ) // Smaller means less powerful. Converting & -> &mut is invalid
+ {
+ // Borrow types aren't compatible
+ DEBUG("BT " << o_bty << " > " << src_bty);
+ break;
+ }
+ // TODO: Check if unsize is possible from `dty` to `oty`
+ if( oty )
+ {
+ DEBUG(" > " << *dty << " =? " << *oty);
+ auto cmp = check_unsize_tys(context, sp, *oty, *dty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality )
+ {
+ //TODO(sp, "Impossibility for " << *oty << " := " << *dty);
+ }
+ else if( cmp == CoerceResult::Unknown )
+ {
+ }
+ else
+ {
+ remove_option = true;
+ DEBUG("- Remove " << *it << ", can deref to " << other_opt);
+ break;
+ }
}
}
+ }
+ }
+ if( !remove_option && !it->ty->m_data.is_Infer() && check_ivar_poss__fails_bounds(sp, context, ty_l, *it->ty) )
+ {
+ remove_option = true;
+ DEBUG("- Remove " << *it << " due to bounds");
+ }
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
+ }
+ DEBUG("possible_tys = " << possible_tys << " (" << n_src_ivars << " src ivars, " << n_dst_ivars << " dst ivars)");
- if( !remove && !allow_unsized )
+ // Find a CD option that can deref to a `--` option
+ for(const auto& e : possible_tys)
+ {
+ if( e.is_pointer && e.can_deref )
+ {
+ ::HIR::TypeRef tmp;
+ const auto* dty = context.m_resolve.autoderef(sp, *e.ty, tmp);
+ if( dty && !dty->m_data.is_Infer() )
+ {
+ for(const auto& e2 : possible_tys)
{
- if( context.m_resolve.type_is_sized(sp, new_ty) == ::HIR::Compare::Unequal )
+ if( !e2.is_pointer && !e2.can_deref )
{
- remove = true;
- DEBUG("Remove possibility " << new_ty << " because it isn't Sized");
+ if( context.m_ivars.types_equal(*dty, *e2.ty) )
+ {
+ DEBUG("Coerce source can deref once to an unsize destination, picking source " << *e.ty);
+ context.equate_types(sp, ty_l, *e.ty);
+ return true;
+ }
}
}
}
-
- if( remove ) {
- it = types_from.erase(it);
- }
- else {
- ++it;
- }
}
+ }
- // Eliminate `to` types that can't be coerced from `from` types
- if(types_from.size() > 0)
- for(auto it = types_to.begin(); it != types_to.end(); )
+ // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it
+ //if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) )
+ if( possible_tys.size() == 1 && n_ivars == 0 )
+ {
+ const auto& new_ty = *possible_tys[0].ty;
+ DEBUG("Only " << new_ty << " is an option");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ // If there's only one non-deref in the list OR there's only one deref in the list
+ if( !honour_disable && n_src_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }) == 1 )
+ {
+ auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; });
+ const auto& new_ty = *it->ty;
+ DEBUG("Picking " << new_ty << " as the only source [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ if( !honour_disable && n_dst_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }) == 1 )
+ {
+ auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; });
+ const auto& new_ty = *it->ty;
+ if( it->is_pointer )
{
- if( it->m_data.is_Infer() ) {
- ++ it;
- continue;
- }
- bool remove = false;
+ DEBUG("Picking " << new_ty << " as the only target [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ else
+ {
+ // HACK: Work around failure in librustc
+ DEBUG("Would pick " << new_ty << " as the only target, but it's an unsize");
+ }
+ }
+ // If there's multiple possiblilties, we're in fallback mode, AND there's no ivars in the list
+ if( possible_tys.size() > 0 && !honour_disable && n_ivars == 0 )
+ {
+ //::std::sort(possible_tys.begin(), possible_tys.end()); // Sorts ivars to the front
+ const auto& new_ty = *possible_tys.back().ty;
+ DEBUG("Picking " << new_ty << " as an arbitary an option from [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
- for(const auto& src : types_from)
- {
- if( H::cannot_coerce_to(context, *it, src) ) {
- remove = true;
- DEBUG("Remove target type " << *it << " because it cannot be created from a source type");
- break;
+ // If there's no ivars, and no instances of &_ or Box<_>, then error/bug here.
+#if 0
+ if( possible_tys.size() > 0 )
+ {
+ struct H {
+ static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) {
+ const auto& t = context.m_ivars.get_type(t_raw);
+ if( const auto* te = t.m_data.opt_Borrow() ) {
+ return get_pointer_inner(context, *te->inner);
}
- }
-
- if( !remove && !allow_unsized )
- {
- if( context.m_resolve.type_is_sized(sp, *it) == ::HIR::Compare::Unequal )
+ else if( const auto* te = t.m_data.opt_Pointer() ) {
+ return get_pointer_inner(context, *te->inner);
+ }
+ else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
- remove = true;
- DEBUG("Remove possibility " << *it << " because it isn't Sized");
+ const auto& te = t.m_data.as_Path();
+ auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ const auto& path = te.path.m_data.as_Generic();
+ return get_pointer_inner(context, path.m_params.m_types.at(param_idx));
+ }
+ else {
+ return t;
}
}
-
- if( remove ) {
- it = types_to.erase(it);
+ };
+ bool has_all_info = true;
+ if( n_ivars > 0 )
+ {
+ has_all_info = false;
+ }
+ for(const auto& e : possible_tys)
+ {
+ const auto& inner = H::get_pointer_inner(context, *e.ty);
+ DEBUG(e << ", inner=" << inner);
+ if( inner.m_data.is_Infer() )
+ {
+ has_all_info = false;
}
- else {
- ++it;
+ if( TU_TEST1(inner.m_data, Path, .binding.is_Unbound()) )
+ {
+ has_all_info = false;
}
}
- }
-
- // De-duplicate lists (after unification) using strict equality
- H::dedup_type_list_with(types_from, [&](const auto& l, const auto& r) {
- return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both;
- });
- H::dedup_type_list_with(types_to, [&](const auto& l, const auto& r) {
- return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both;
- });
-
- // If there is a common type in both lists, use it
- for(const auto& t1 : types_from)
- {
- for(const auto& t2 : types_to)
+ if( has_all_info )
{
- if(t1 == t2) {
- DEBUG("- IVar " << ty_l << " = " << t1 << " (present in both lists)");
- context.equate_types(sp, ty_l, t1);
- return true;
- }
+ BUG(sp, "Sufficient information for " << ty_l << " but didn't pick a type - options are [" << possible_tys << "]");
}
}
+#endif
- // Prefer cases where this type is being created from a known type
- if( types_from.size() == 1 || types_to.size() == 1 ) {
- const char* list_name = (types_from.size() ? "from" : "to");
- const ::HIR::TypeRef& ty_r = (types_from.size() == 1 ? types_from[0] : types_to[0]);
- // Only one possibility
- // - If it would ivar unify, don't if the target has guessing disabled
- if( const auto* e = ty_r.m_data.opt_Infer() )
+ // If only one bound meets the possible set, use it
+ if( ! possible_tys.empty() )
+ {
+ DEBUG("Checking bounded [" << ivar_ent.bounded << "]");
+ ::std::vector<const ::HIR::TypeRef*> feasable_bounds;
+ for(const auto& new_ty : ivar_ent.bounded)
{
- if( e->index < context.possible_ivar_vals.size() )
+ bool failed_a_bound = false;
+ // TODO: Check if this bounded type _cannot_ work with any of the existing bounds
+ // - Don't add to the possiblity list if so
+ for(const auto& opt : possible_tys)
{
- const auto& p = context.possible_ivar_vals[e->index];
- if( honour_disable && (p.force_no_to || p.force_no_from) )
- {
- DEBUG("- IVar " << ty_l << " ?= " << ty_r << " (single " << list_name << ", rhs disabled)");
- return false;
+ if( opt.can_deref ) {
+ const auto* dty = opt.ty;
+
+ DEBUG(" > " << new_ty << " =? " << *dty);
+ auto cmp = check_unsize_tys(context, sp, new_ty, *dty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
+ }
+ else {
+ // Destination type, this option must deref to it
+ DEBUG(" > " << *opt.ty << " =? " << new_ty);
+ auto cmp = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
}
}
+ // TODO: Should this also check check_ivar_poss__fails_bounds
+ if( !failed_a_bound )
+ {
+ feasable_bounds.push_back(&new_ty);
+ }
}
- // If there are from options, AND the to option is an Unsize
- if( types_from.size() > 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_to.size() == 0
- && ::std::any_of(types_from.begin(), types_from.end(), [](const auto&x){ return x.m_data.is_Infer(); }) ) {
- DEBUG("- IVar " << ty_l << " != " << ty_r << " (single " << list_name << ", but was unsize and from has ivars)");
- return false;
+ if( feasable_bounds.size() == 1 )
+ {
+ const auto& new_ty = *feasable_bounds.front();
+ DEBUG("Picking " << new_ty << " as it's the only bound that fits coercions");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
}
-
- DEBUG("- IVar " << ty_l << " = " << ty_r << " (single " << list_name << ")");
- context.equate_types(sp, ty_l, ty_r);
- return true;
}
- else {
- DEBUG("- IVar " << ty_l << " not concretely known {" << types_from << "} and {" << types_to << "}" );
+ else
+ {
+ // Not checking bounded list, because there's nothing to check
+ }
+
+ has_no_coerce_posiblities = possible_tys.empty() && n_ivars == 0;
+ }
- // If one side is completely unknown, pick the most liberal of the other side
- if( types_to.size() == 0 && types_from.size() > 0 )
+ if( has_no_coerce_posiblities && !ivar_ent.bounded.empty() )
+ {
+ // TODO: Search know possibilties and check if they satisfy the bounds for this ivar
+ DEBUG("Options: " << ivar_ent.bounded);
+ unsigned int n_good_ints = 0;
+ ::std::vector<const ::HIR::TypeRef*> good_types;
+ good_types.reserve(ivar_ent.bounded.size());
+ for(const auto& new_ty : ivar_ent.bounded)
+ {
+ DEBUG("- Test " << new_ty << " against current rules");
+ if( check_ivar_poss__fails_bounds(sp, context, ty_l, new_ty) )
{
- // Search for the lowest-level source type (e.g. &[T])
- const auto* lowest_type = H::find_lowest_type(context, types_from);
- if( lowest_type )
- {
- const ::HIR::TypeRef& ty_r = *lowest_type;
- DEBUG("- IVar " << ty_l << " = " << ty_r << " (from, lowest)");
- context.equate_types(sp, ty_l, ty_r);
- return true;
- }
}
- else if( types_to.size() > 0 && types_from.size() == 0 )
+ else
+ {
+ good_types.push_back(&new_ty);
+
+ if( new_ty.m_data.is_Primitive() )
+ n_good_ints ++;
+
+ DEBUG("> " << new_ty << " feasible");
+ }
+ }
+ DEBUG(good_types.size() << " valid options (" << n_good_ints << " primitives)");
+ // Picks the first if in fallback mode (which is signalled by `honour_disable` being false)
+ // - This handles the case where there's multiple valid options (needed for libcompiler_builtins)
+ // TODO: Only pick any if all options are the same class (or just all are integers)
+ if( good_types.empty() )
+ {
+
+ }
+ else if( good_types.size() == 1 )
+ {
+ // Since it's the only possibility, choose it?
+ DEBUG("Only " << *good_types.front() << " fits current bound sets");
+ context.equate_types(sp, ty_l, *good_types.front());
+ return true;
+ }
+ else if( good_types.size() > 0 && fallback_ty == IvarPossFallbackType::FinalOption )
+ {
+ auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); };
+ // NOTE: We want to select from sets of primitives and generics (which can be interchangable)
+ if( ::std::all_of(good_types.begin(), good_types.end(), typ_is_borrow) == ::std::any_of(good_types.begin(), good_types.end(), typ_is_borrow) )
{
- // TODO: Get highest-level target type
+ DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options [" << FMT_CB(ss, for(auto e:good_types) ss << *e << ",";) << "]");
+ context.equate_types(sp, ty_l, *good_types.front());
+ return true;
}
else
{
+ // Mix of borrows with non-borrows
}
}
}
@@ -6085,10 +8385,11 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
TRACE_FUNCTION;
auto root_ptr = expr.into_unique();
- Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics };
+ assert(!ms.m_mod_paths.empty());
+ Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics, ms.m_mod_paths.back() };
for( auto& arg : args ) {
- context.add_binding( Span(), arg.first, arg.second );
+ context.handle_pattern( Span(), arg.first, arg.second );
}
// - Build up ruleset from node tree
@@ -6120,11 +8421,18 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
return false;
});
+ if(true)
+ {
+ ExprVisitor_AddIvars visitor(context);
+ context.add_ivars(root_ptr->m_res_type);
+ root_ptr->visit(visitor);
+ }
+
ExprVisitor_Enum visitor(context, ms.m_traits, result_type);
context.add_ivars(root_ptr->m_res_type);
root_ptr->visit(visitor);
- DEBUG("Return type = " << new_res_ty);
+ DEBUG("Return type = " << new_res_ty << ", root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type);
context.equate_types_coerce(sp, new_res_ty, root_ptr);
}
@@ -6149,6 +8457,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
DEBUG("- Consumed coercion " << ent.left_ty << " := " << src_ty);
+#if 0
// If this isn't the last item in the list
if( i != context.link_coerce.size() - 1 )
{
@@ -6157,6 +8466,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
// Remove the last item.
context.link_coerce.pop_back();
+#else
+ context.link_coerce.erase( context.link_coerce.begin() + i );
+#endif
}
else
{
@@ -6177,6 +8489,10 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
if( rule.name != "" ) {
rule.left_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.left_ty));
+ // HACK: If the left type is `!`, remove the type bound
+ //if( rule.left_ty.m_data.is_Diverge() ) {
+ // rule.name = "";
+ //}
}
rule.impl_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.impl_ty));
@@ -6217,14 +8533,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
++ it;
}
}
- for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
{
- auto& ent = **it;
- if( ent.revisit(context) ) {
- it = context.adv_revisits.erase(it);
+ ::std::vector<bool> adv_revisit_remove_list;
+ size_t len = context.adv_revisits.size();
+ for(size_t i = 0; i < len; i ++)
+ {
+ auto& ent = *context.adv_revisits[i];
+ adv_revisit_remove_list.push_back( ent.revisit(context, /*is_fallback=*/false) );
}
- else {
- ++ it;
+ for(size_t i = len; i --;)
+ {
+ if( adv_revisit_remove_list[i] ) {
+ context.adv_revisits.erase( context.adv_revisits.begin() + i );
+ }
}
}
@@ -6234,12 +8555,13 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
// Check the possible equations
DEBUG("--- IVar possibilities");
- // NOTE: Ordering is a hack for libgit2
- for(unsigned int i = context.possible_ivar_vals.size(); i --; )
+ // TODO: De-duplicate this with the block ~80 lines below
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i]) ) {
static Span sp;
- assert( context.possible_ivar_vals[i].has_rules() );
+ //assert( context.possible_ivar_vals[i].has_rules() );
// Disable all metioned ivars in the possibilities
for(const auto& ty : context.possible_ivar_vals[i].types_coerce_to)
context.equate_types_from_shadow(sp,ty);
@@ -6251,6 +8573,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
context.equate_types_to_shadow(sp,ty);
// Also disable inferrence (for this pass) for all ivars in affected bounds
+ if(false)
for(const auto& la : context.link_assoc)
{
bool found = false;
@@ -6276,47 +8599,70 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
} // `if peek_changed` (ivar possibilities)
+#if 0
if( !context.m_ivars.peek_changed() )
{
- DEBUG("--- Node revisits (fallback)");
- for( auto it = context.to_visit.begin(); it != context.to_visit.end(); )
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
{
- ::HIR::ExprNode& node = **it;
- ExprVisitor_Revisit visitor { context, true };
- DEBUG("> " << &node << " " << typeid(node).name() << " -> " << context.m_ivars.fmt_type(node.m_res_type));
- node.visit( visitor );
- // - If the node is completed, remove it
- if( visitor.node_completed() ) {
- DEBUG("- Completed " << &node << " - " << typeid(node).name());
- it = context.to_visit.erase(it);
- }
- else {
- ++ it;
- }
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
+
+ context.equate_types(sp, ent.left_ty, src_ty);
}
- #if 0
- for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
+ }
+#endif
+ // If nothing has changed, run check_ivar_poss again but allow it to assume is has all the options
+ if( !context.m_ivars.peek_changed() )
+ {
+ // Check the possible equations
+ DEBUG("--- IVar possibilities (fallback 1)");
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
- auto& ent = **it;
- if( ent.revisit(context, true) ) {
- it = context.adv_revisits.erase(it);
- }
- else {
- ++ it;
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::Assume) ) {
+ break;
}
}
- #endif
- } // `if peek_changed` (node revisits)
+ }
+#if 0
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
+ {
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
+ context.equate_types(sp, ent.left_ty, src_ty);
+ }
+ }
+#endif
// If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag
+#if 1
if( !context.m_ivars.peek_changed() )
{
// Check the possible equations
DEBUG("--- IVar possibilities (fallback)");
- // NOTE: Ordering is a hack for libgit2
- for(unsigned int i = context.possible_ivar_vals.size(); i --; )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
- if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) {
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::IgnoreWeakDisable) ) {
+# if 1
+ break;
+# else
static Span sp;
assert( context.possible_ivar_vals[i].has_rules() );
// Disable all metioned ivars in the possibilities
@@ -6348,13 +8694,95 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
context.equate_types_shadow(sp, t, false);
}
}
+# endif
}
else {
//assert( !context.m_ivars.peek_changed() );
}
}
+#endif
} // `if peek_changed` (ivar possibilities #2)
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Node revisits (fallback)");
+ for( auto it = context.to_visit.begin(); it != context.to_visit.end(); )
+ {
+ ::HIR::ExprNode& node = **it;
+ ExprVisitor_Revisit visitor { context, true };
+ DEBUG("> " << &node << " " << typeid(node).name() << " -> " << context.m_ivars.fmt_type(node.m_res_type));
+ node.visit( visitor );
+ // - If the node is completed, remove it
+ if( visitor.node_completed() ) {
+ DEBUG("- Completed " << &node << " - " << typeid(node).name());
+ it = context.to_visit.erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ #if 0
+ for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
+ {
+ auto& ent = **it;
+ if( ent.revisit(context, true) ) {
+ it = context.adv_revisits.erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ #endif
+ } // `if peek_changed` (node revisits)
+
+ if( !context.m_ivars.peek_changed() )
+ {
+ size_t len = context.adv_revisits.size();
+ for(size_t i = 0; i < len; i ++)
+ {
+ auto& ent = *context.adv_revisits[i];
+ ent.revisit(context, /*is_fallback=*/true);
+ if( context.m_ivars.peek_changed() ) {
+ break;
+ }
+ }
+ }
+
+#if 1
+ if( !context.m_ivars.peek_changed() )
+ {
+ // Check the possible equations
+ DEBUG("--- IVar possibilities (final fallback)");
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ {
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::FinalOption) ) {
+ break;
+ }
+ }
+ }
+#endif
+
+#if 1
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
+ {
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion " << ent.left_ty << " := " << src_ty);
+
+ context.equate_types(sp, ent.left_ty, src_ty);
+ }
+ }
+#endif
+
// Finally. If nothing changed, apply ivar defaults
if( !context.m_ivars.peek_changed() )
{
@@ -6404,14 +8832,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
const auto& sp = node->span();
if( const auto* np = dynamic_cast<::HIR::ExprNode_CallMethod*>(node) )
{
- WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method);
+ WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method << " -> " << context.m_ivars.fmt_type(np->m_res_type));
}
else
{
}
}
+ for(const auto& adv : context.adv_revisits)
+ {
+ WARNING(adv->span(), W0000, "Spare Rule - " << FMT_CB(os, adv->fmt(os)));
+ }
BUG(root_ptr->span(), "Spare rules left after typecheck stabilised");
}
+ DEBUG("root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type);
// - Recreate the pointer
expr.reset( root_ptr.release() );
@@ -6429,5 +8862,18 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
ExprVisitor_Apply visitor { context };
visitor.visit_node_ptr( expr );
}
+
+ {
+ StaticTraitResolve static_resolve(ms.m_crate);
+ if( ms.m_impl_generics )
+ {
+ static_resolve.set_impl_generics_raw(*ms.m_impl_generics);
+ }
+ if( ms.m_item_generics )
+ {
+ static_resolve.set_item_generics_raw(*ms.m_item_generics);
+ }
+ Typecheck_Expressions_ValidateOne(static_resolve, args, result_type, expr);
+ }
}
diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp
index 1a153aaf..df27b7d7 100644
--- a/src/hir_typeck/expr_visit.cpp
+++ b/src/hir_typeck/expr_visit.cpp
@@ -19,6 +19,90 @@ void Typecheck_Code(const typeck::ModuleState& ms, t_args& args, const ::HIR::Ty
}
}
+namespace typeck {
+ void ModuleState::prepare_from_path(const ::HIR::ItemPath& ip)
+ {
+ static Span sp;
+ ASSERT_BUG(sp, ip.parent, "prepare_from_path with too-short path - " << ip);
+ struct H {
+ static const ::HIR::Module& get_mod_for_ip(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip)
+ {
+ if( ip.parent )
+ {
+ const auto& mod = H::get_mod_for_ip(crate, *ip.parent);
+ return mod.m_mod_items.at(ip.name)->ent.as_Module();
+ }
+ else
+ {
+ assert(ip.crate_name);
+ return (ip.crate_name[0] ? crate.m_ext_crates.at(ip.crate_name).m_data->m_root_module : crate.m_root_module);
+ }
+ }
+ static void add_traits_from_mod(ModuleState& ms, const ::HIR::Module& mod)
+ {
+ // In-scope traits.
+ ms.m_traits.clear();
+ for(const auto& tp : mod.m_traits)
+ {
+ const auto& trait = ms.m_crate.get_trait_by_path(sp, tp);
+ ms.m_traits.push_back(::std::make_pair( &tp, &trait ));
+ }
+ }
+ };
+ if( ip.parent->trait && ip.parent->ty )
+ {
+ // Trait impl
+ TODO(sp, "prepare_from_path - Trait impl " << ip);
+ }
+ else if( ip.parent->trait )
+ {
+ // Trait definition
+ //const auto& trait_mod = H::get_mod_for_ip(m_crate, *ip.parent->trait->parent);
+ //const auto& trait = trait_mod.m_mod_items.at(ip.parent->trait->name).ent.as_Trait();
+ const auto& trait = m_crate.get_trait_by_path(sp, *ip.parent->trait);
+ const auto& item = trait.m_values.at(ip.name);
+ TU_MATCH_HDRA( (item), { )
+ TU_ARMA(Function, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Constant, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Static, e) {
+ m_item_generics = nullptr;
+ }
+ }
+ }
+ else if( ip.parent->ty )
+ {
+ // Inherent impl
+ TODO(sp, "prepare_from_path - Type impl " << ip);
+ }
+ else
+ {
+ // Namespace path
+ const auto& mod = H::get_mod_for_ip(m_crate, *ip.parent);
+ H::add_traits_from_mod(*this, mod);
+ const auto& item = mod.m_value_items.at(ip.name)->ent;
+ m_impl_generics = nullptr;
+ TU_MATCH_HDRA( (item), { )
+ TU_ARMA(Constant, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Static, e) {
+ //m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Function, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(StructConstant, _e) BUG(sp, ip << " is StructConstant");
+ TU_ARMA(StructConstructor, _e) BUG(sp, ip << " is StructConstructor");
+ TU_ARMA(Import, _e) BUG(sp, ip << " is Import");
+ }
+ }
+ }
+} // namespace typeck
+
namespace {
@@ -36,7 +120,7 @@ namespace {
public:
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
{
- m_ms.push_traits(mod);
+ m_ms.push_traits(p, mod);
::HIR::Visitor::visit_module(p, mod);
m_ms.pop_traits(mod);
}
@@ -58,7 +142,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
::HIR::Visitor::visit_type_impl(impl);
m_ms.pop_traits(mod);
}
@@ -68,7 +152,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) );
::HIR::Visitor::visit_trait_impl(trait_path, impl);
m_ms.m_traits.pop_back( );
@@ -80,7 +164,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
::HIR::Visitor::visit_marker_impl(trait_path, impl);
m_ms.pop_traits(mod);
}
diff --git a/src/hir_typeck/expr_visit.hpp b/src/hir_typeck/expr_visit.hpp
index 21a775dc..fbd22704 100644
--- a/src/hir_typeck/expr_visit.hpp
+++ b/src/hir_typeck/expr_visit.hpp
@@ -5,16 +5,18 @@
* hir_typeck/expr_visit.hpp
* - Helpers for the HIR typecheck expression visiting
*/
+#include <hir/item_path.hpp>
namespace typeck {
struct ModuleState
{
const ::HIR::Crate& m_crate;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits;
+ ::std::vector<HIR::SimplePath> m_mod_paths;
ModuleState(const ::HIR::Crate& crate):
m_crate(crate),
@@ -33,19 +35,22 @@ namespace typeck {
ptr = nullptr;
}
};
- NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
assert( !m_impl_generics );
m_impl_generics = &gps;
- return NullOnDrop< ::HIR::GenericParams>(m_impl_generics);
+ return NullOnDrop<const ::HIR::GenericParams>(m_impl_generics);
}
- NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
assert( !m_item_generics );
m_item_generics = &gps;
- return NullOnDrop< ::HIR::GenericParams>(m_item_generics);
+ return NullOnDrop<const ::HIR::GenericParams>(m_item_generics);
}
- void push_traits(const ::HIR::Module& mod) {
+ void prepare_from_path(const ::HIR::ItemPath& ip);
+
+ void push_traits(::HIR::ItemPath p, const ::HIR::Module& mod) {
auto sp = Span();
+ m_mod_paths.push_back( p.get_simple_path() );
DEBUG("Module has " << mod.m_traits.size() << " in-scope traits");
// - Push a NULL entry to prevent parent module import lists being searched
m_traits.push_back( ::std::make_pair(nullptr, nullptr) );
@@ -59,6 +64,7 @@ namespace typeck {
for(unsigned int i = 0; i < mod.m_traits.size(); i ++ )
m_traits.pop_back();
m_traits.pop_back();
+ m_mod_paths.pop_back();
}
};
}
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index 0a56e9cb..010df546 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -188,17 +188,17 @@ bool HMTypeInferrence::apply_defaults()
break;
case ::HIR::InferClass::Diverge:
rv = true;
- DEBUG("- " << *v.type << " -> !");
+ DEBUG("- IVar " << e.index << " = !");
*v.type = ::HIR::TypeRef(::HIR::TypeRef::Data::make_Diverge({}));
break;
case ::HIR::InferClass::Integer:
rv = true;
- DEBUG("- " << *v.type << " -> i32");
+ DEBUG("- IVar " << e.index << " = i32");
*v.type = ::HIR::TypeRef( ::HIR::CoreType::I32 );
break;
case ::HIR::InferClass::Float:
rv = true;
- DEBUG("- " << *v.type << " -> f64");
+ DEBUG("- IVar " << e.index << " = f64");
*v.type = ::HIR::TypeRef( ::HIR::CoreType::F64 );
break;
}
@@ -558,30 +558,38 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
DEBUG("set_ivar_to(" << slot << " { " << *root_ivar.type << " }, " << type << ")");
// If the left type was '_', alias the right to it
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Infer, l_e,
- assert( l_e.index != slot );
- DEBUG("Set IVar " << slot << " = @" << l_e.index);
-
- if( l_e.ty_class != ::HIR::InferClass::None ) {
+ if( const auto* l_e = type.m_data.opt_Infer() )
+ {
+ assert( l_e->index != slot );
+ if( l_e->ty_class != ::HIR::InferClass::None ) {
TU_MATCH_DEF(::HIR::TypeRef::Data, (root_ivar.type->m_data), (e),
(
ERROR(sp, E0000, "Type unificiation of literal with invalid type - " << *root_ivar.type);
),
(Primitive,
- check_type_class_primitive(sp, type, l_e.ty_class, e);
+ check_type_class_primitive(sp, type, l_e->ty_class, e);
),
(Infer,
// Check for right having a ty_class
- if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e.ty_class ) {
+ if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e->ty_class ) {
ERROR(sp, E0000, "Unifying types with mismatching literal classes - " << type << " := " << *root_ivar.type);
}
)
)
}
- root_ivar.alias = l_e.index;
+ #if 1
+ // Alias `l_e.index` to this slot
+ DEBUG("Set IVar " << l_e->index << " = @" << slot);
+ auto& r_ivar = this->get_pointed_ivar(l_e->index);
+ r_ivar.alias = slot;
+ r_ivar.type.reset();
+ #else
+ DEBUG("Set IVar " << slot << " = @" << l_e->index);
+ root_ivar.alias = l_e->index;
root_ivar.type.reset();
- )
+ #endif
+ }
else if( *root_ivar.type == type ) {
return ;
}
@@ -597,13 +605,15 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
case ::HIR::InferClass::Integer:
case ::HIR::InferClass::Float:
// `type` can't be an ivar, so it has to be a primitive (or an associated?)
- TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (l_e),
- (
- ),
- (Primitive,
- check_type_class_primitive(sp, type, e.ty_class, l_e);
- )
- )
+ if( const auto* l_e = type.m_data.opt_Primitive() ) {
+ check_type_class_primitive(sp, type, e.ty_class, *l_e);
+ }
+ else if( type.m_data.is_Diverge() ) {
+ // ... acceptable
+ }
+ else {
+ BUG(sp, "Setting primitive to " << type);
+ }
break;
}
)
@@ -617,9 +627,13 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
}
#if 1
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Diverge, e,
- root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge;
- )
+ if( type.m_data.is_Diverge() )
+ {
+ if( root_ivar.type->m_data.as_Infer().ty_class == ::HIR::InferClass::None )
+ {
+ root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge;
+ }
+ }
else
#endif
root_ivar.type = box$( type );
@@ -914,8 +928,8 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe
return pathparams_equal(le.m_trait.m_path.m_params, re.m_trait.m_path.m_params);
),
(ErasedType,
+ ASSERT_BUG(Span(), le.m_origin != ::HIR::SimplePath(), "Erased type with unset origin");
return H::compare_path(*this, le.m_origin, re.m_origin);
- //TODO(Span(), "ErasedType");
),
(Tuple,
return type_list_equal(*this, le, re);
@@ -932,13 +946,26 @@ void TraitResolution::prep_indexes()
static Span sp_AAA;
const Span& sp = sp_AAA;
+ // TODO: Create a list of all known type rules in this scope (recursively)
+ // - What if there's recursive bounds (e.g. on ATYs)
+
auto add_equality = [&](::HIR::TypeRef long_ty, ::HIR::TypeRef short_ty){
DEBUG("[prep_indexes] ADD " << long_ty << " => " << short_ty);
// TODO: Sort the two types by "complexity" (most of the time long >= short)
this->m_type_equalities.insert(::std::make_pair( mv$(long_ty), mv$(short_ty) ));
};
+ DEBUG("m_impl_params = " << m_impl_params << ", m_item_params = " << m_item_params);
+ if( m_impl_params ) {
+ DEBUG("- impl" << m_impl_params->fmt_args() << " " << m_impl_params->fmt_bounds());
+ }
+ if( m_item_params ) {
+ DEBUG("- fn ..." << m_item_params->fmt_args() << " " << m_item_params->fmt_bounds());
+ }
+ // Obtain type equality bounds.
+ // TODO: Also flatten the bounds list into known trait bounds?
this->iterate_bounds([&](const auto& b)->bool {
+ DEBUG("[prep_indexes] " << b);
if(const auto* bep = b.opt_TraitBound())
{
const auto& be = *bep;
@@ -949,7 +976,7 @@ void TraitResolution::prep_indexes()
// Locate the source trait
::HIR::GenericPath source_trait_path;
- bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first, source_trait_path);
+ bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first.c_str(), source_trait_path);
ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << be.trait.m_path);
auto ty_l = ::HIR::TypeRef( ::HIR::Path( be.type.clone(), mv$(source_trait_path), tb.first ) );
@@ -994,7 +1021,7 @@ void TraitResolution::prep_indexes()
// Find the source trait for this associated type
::HIR::GenericPath source_trait_path;
- bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first, source_trait_path);
+ bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first.c_str(), source_trait_path);
ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << trait_mono.m_path);
auto ty_l = ::HIR::TypeRef( ::HIR::Path( ty_a.clone(), mv$(source_trait_path), tb.first ) );
@@ -1047,11 +1074,42 @@ bool TraitResolution::iterate_bounds( ::std::function<bool(const ::HIR::GenericB
}
return false;
}
+bool TraitResolution::iterate_bounds_traits(const Span& sp, ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::TraitPath& trait)> cb) const
+{
+ // Iterate all bounds, finding trait
+ return this->iterate_bounds([&](const auto& gb) {
+ if( const auto* be = gb.opt_TraitBound() )
+ {
+ // TODO: Type filter (to avoid the cost of checking parent bounds)
+ if( cb(be->type, be->trait) )
+ return true;
+
+ // TODO: Remove, or fix places where `find_named_trait_in_trait` is used along with this function
+ // - Using both leads to duplicate detections, which can confuse callers
+#if 0
+ assert(be->trait.m_trait_ptr);
+ const auto& trait_ref = *be->trait.m_trait_ptr;
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &be->type, &be->trait.m_path.m_params, nullptr, nullptr);
+ for(const auto& parent_tp : trait_ref.m_all_parent_traits)
+ {
+ ::HIR::TraitPath tp_mono_o;
+ const auto& tp_mono = (monomorphise_traitpath_needed(parent_tp) ? tp_mono_o = monomorphise_traitpath_with(sp, parent_tp, monomorph_cb, false) : parent_tp);
+ // TODO: Monomorphise the bound
+ if( cb(be->type, tp_mono) )
+ return true;
+ }
+#endif
+ }
+ return false;
+ });
+}
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;
- if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, 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.c_str(), 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;
@@ -1084,37 +1142,23 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data
return false;
}
-bool TraitResolution::find_trait_impls(const Span& sp,
+bool TraitResolution::find_trait_impls_magic(const Span& sp,
const ::HIR::SimplePath& trait, const ::HIR::PathParams& params,
const ::HIR::TypeRef& ty,
t_cb_trait_impl_r callback
) const
{
static ::HIR::PathParams null_params;
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
-
- const auto& type = this->m_ivars.get_type(ty);
- TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
-
-#if 0
- if( const auto* te = type.m_data.opt_Infer() )
- {
- if( !te->is_lit() ) {
- // NOTE: Can't hope to find an impl if we know nothing about the type.
- return false;
- }
- }
-#endif
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
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");
- const auto& trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut");
- const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once");
- 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");
+
+ const auto& type = this->m_ivars.get_type(ty);
+ TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
if( trait == lang_Sized ) {
auto cmp = type_is_sized(sp, type);
@@ -1136,6 +1180,105 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
}
+ 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;
+ }
+ }
+
+ // 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;
+
+ 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;
+ }
+
+ // 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;
+ }
+ }
+ }
+ )
+ )
+ }
+
+ return false;
+}
+
+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,
+ bool magic_trait_impls /*=true*/
+ ) const
+{
+ static ::HIR::PathParams null_params;
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
+
+ const auto& type = this->m_ivars.get_type(ty);
+ TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
+
+#if 0
+ if( const auto* te = type.m_data.opt_Infer() )
+ {
+ if( !te->is_lit() ) {
+ // NOTE: Can't hope to find an impl if we know nothing about the type.
+ return false;
+ }
+ }
+#endif
+
+ const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn");
+ const auto& trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut");
+ const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once");
+ 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( magic_trait_impls )
+ {
+ if( find_trait_impls_magic(sp, trait, params, ty, callback) ) {
+ return true;
+ }
+ }
+
// Magic impls of the Fn* traits for closure types
TU_IFLET(::HIR::TypeRef::Data, type.m_data, Closure, e,
DEBUG("Closure, " << trait << " ?= " << trait_fn << " " << trait_fn_mut << " " << trait_fn_once);
@@ -1168,7 +1311,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
::HIR::PathParams pp;
pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1210,7 +1353,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
::HIR::PathParams pp;
pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1235,7 +1378,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
{
::HIR::PathParams pp;
pp.m_types.push_back( mv$(ty_usize) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.inner->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1275,8 +1418,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
if( trait == mt.m_path ) {
auto cmp = compare_pp(sp, mt.m_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
- static ::std::map< ::std::string, ::HIR::TypeRef> types;
- return callback( ImplRef(&type, &mt.m_params, &types), cmp );
+ return callback( ImplRef(&type, &mt.m_params, &null_assoc), cmp );
}
}
}
@@ -1290,7 +1432,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
auto cmp = this->compare_pp(sp, i_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map<RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone));
@@ -1327,7 +1469,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
auto cmp = this->compare_pp(sp, i_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map<RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone));
@@ -1361,12 +1503,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<RcString, ::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,28 +1524,32 @@ 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;
}
}
}
+ bool rv = false;
bool ret = this->find_named_trait_in_trait(sp, trait, params, *bound.m_trait_ptr, bound.m_path.m_path, b_params_mono, type,
[&](const auto& i_ty, const auto& i_params, const auto& i_assoc) {
auto cmp = this->compare_pp(sp, i_params, params);
DEBUG("cmp=" << cmp << ", impl " << trait << i_params << " for " << i_ty << " -- desired " << trait << params);
- return cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp );
+ rv |= (cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp ));
+ return true; // NOTE: actually ignored?
});
if( ret )
{
// NOTE: Callback called in closure's return statement
- return true;
+ return rv;
}
return false;
});
@@ -1405,55 +1558,6 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
)
- // 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;
-
- 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;
- }
-
- // 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
if( find_trait_impls_bound(sp, trait, params, type, callback) )
return true;
@@ -1898,7 +2002,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
(
),
(TraitBound,
- DEBUG("Trait bound - " << be.type << " : " << be.trait);
+ DEBUG("[expand_associated_types_inplace__UfcsKnown] Trait bound - " << be.type << " : " << be.trait);
// 1. Check if the type matches
// - TODO: This should be a fuzzier match?
if( be.type != *pe.type )
@@ -1910,7 +2014,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
if( it == be.trait.m_type_bounds.end() ) {
// If not, assume it's opaque and return as such
// TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
- DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
+ DEBUG("[expand_associated_types_inplace__UfcsKnown] Found impl for " << input << " but no bound on item, assuming opaque");
}
else {
assume_opaque = false;
@@ -1983,6 +2087,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
}
// If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality
+ // e.g. `<<Foo as Bar>::Baz as Trait2>::Type` may have an ATY bound `trait Bar { type Baz: Trait2<Type=...> }`
// Use bounds on other associated types too (if `pe.type` was resolved to a fixed associated type)
TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Path, te_inner,
TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner,
@@ -1990,7 +2095,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
// - Does simplification of complex associated types
//
::HIR::GenericPath trait_path;
- if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item, trait_path) )
+ if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << pe_inner.item << " anywhere in trait " << pe_inner.trait);
const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, trait_path.m_path);
const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item);
@@ -2016,7 +2121,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
{
// If the bound is for Self and the outer trait
// - TODO: Fuzzy check the parameters?
- if( bound.m_path == pe.trait ) {
+ ::HIR::GenericPath tmp_tp;
+ const auto& bound_tp = monomorphise_genericpath_with_opt(sp, tmp_tp, bound.m_path, cb_placeholders_trait);
+ DEBUG(bound_tp << " ?= " << pe.trait);
+ if( bound_tp == pe.trait ) {
auto it = bound.m_type_bounds.find( pe.item );
if( it != bound.m_type_bounds.end() ) {
if( monomorphise_type_needed(it->second) ) {
@@ -2032,10 +2140,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
}
// TODO: Find trait in this trait.
- const auto& bound_trait = m_crate.get_trait_by_path(sp, bound.m_path.m_path);
+ const auto& bound_trait = m_crate.get_trait_by_path(sp, bound_tp.m_path);
bool replaced = this->find_named_trait_in_trait(sp,
pe.trait.m_path,pe.trait.m_params,
- bound_trait, bound.m_path.m_path,bound.m_path.m_params, *pe.type,
+ bound_trait, bound_tp.m_path,bound_tp.m_params, *pe.type,
[&](const auto&, const auto& x, const auto& assoc){
auto it = assoc.find(pe.item);
if( it != assoc.end() ) {
@@ -2057,7 +2165,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
// TODO: Search for the actual trait containing this associated type
::HIR::GenericPath trait_path;
//if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), *pe.type, pe.item, trait_path) )
- if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) )
+ if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait);
//pe.trait = mv$(trait_path);
@@ -2185,15 +2293,16 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp,
{
auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false);
- DEBUG(pt << " => " << pt_mono);
+ //DEBUG(pt << " => " << pt_mono);
if( pt.m_path.m_path == des ) {
+ //DEBUG("Found potential " << pt_mono);
// NOTE: Doesn't quite work...
//auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params);
//if( cmp != ::HIR::Compare::Unequal )
//{
- callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds );
+ if( callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds ) )
+ return true;
//}
- return true;
}
}
@@ -2209,134 +2318,139 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple
)
)
-#if 0
- if( m_ivars.get_type(type).m_data.is_Infer() )
+ if(type.m_data.is_Infer()) {
return false;
- if( TU_TEST1(m_ivars.get_type(type).m_data, Path, .binding.is_Unbound()) )
- return false;
-#endif
+ }
+
+ // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list.
// 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 {
- if( b.is_TraitBound() )
- {
- const auto& e = b.as_TraitBound();
- const auto& b_params = e.trait.m_path.m_params;
+ // > Would maybe want a list of all explicit and implied bounds instead.
+ return this->iterate_bounds_traits(sp, [&](const auto& bound_ty, const ::HIR::TraitPath& bound_trait)->bool {
+ const auto& b_params = bound_trait.m_path.m_params;
- auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer());
- if( cmp == ::HIR::Compare::Unequal )
+ auto cmp = bound_ty .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer());
+ if( cmp == ::HIR::Compare::Unequal )
+ return false;
+ DEBUG("[find_trait_impls_bound] " << bound_trait << " for " << bound_ty << " cmp = " << cmp);
+
+ if( bound_trait.m_path.m_path == trait ) {
+ // Check against `params`
+ DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params);
+ auto ord = cmp;
+ ord &= this->compare_pp(sp, b_params, params);
+ if( ord == ::HIR::Compare::Unequal )
return false;
-
- if( e.trait.m_path.m_path == trait ) {
- // Check against `params`
- DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params);
- auto ord = cmp;
- ord &= this->compare_pp(sp, b_params, params);
- if( ord == ::HIR::Compare::Unequal )
- return false;
- if( ord == ::HIR::Compare::Fuzzy ) {
- DEBUG("Fuzzy match");
- }
- DEBUG("[find_trait_impls_bound] Match " << b);
- // Hand off to the closure, and return true if it does
- // TODO: The type bounds are only the types that are specified.
- if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) {
- return true;
- }
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
}
+ DEBUG("[find_trait_impls_bound] Match " << bound_ty << " : " << bound_trait);
+ // Hand off to the closure, and return true if it does
+ // TODO: The type bounds are only the types that are specified.
+ auto b = bound_trait.clone();
+ if( callback( ImplRef(bound_ty.clone(), mv$(b.m_path.m_params), mv$(b.m_type_bounds)), ord) ) {
+ return true;
+ }
+ }
- // TODO: Allow fuzzy equality?
- if( cmp == ::HIR::Compare::Equal )
- {
- // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set
- // - XXX: This is actually wrong (false-positive) in many cases. FIXME
- bool rv = this->find_named_trait_in_trait(sp,
- trait,params,
- *e.trait.m_trait_ptr, e.trait.m_path.m_path,e.trait.m_path.m_params,
- type,
- [&](const auto& ty, const auto& params, const auto& assoc) {
- // TODO: Avoid duplicating this map every time
- ::std::map< ::std::string,::HIR::TypeRef> assoc2;
- for(const auto& i : assoc) {
+ // TODO: Allow fuzzy equality?
+ if( cmp == ::HIR::Compare::Equal )
+ {
+ // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set
+ // - XXX: This is actually wrong (false-positive) in many cases. FIXME
+ bool rv = this->find_named_trait_in_trait(sp,
+ trait,params,
+ *bound_trait.m_trait_ptr, bound_trait.m_path.m_path,bound_trait.m_path.m_params,
+ type,
+ [&](const auto& ty, const auto& b_params, const auto& assoc) {
+ // TODO: Avoid duplicating this map every time
+ ::std::map< RcString,::HIR::TypeRef> assoc2;
+ for(const auto& i : assoc) {
+ assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
+ }
+ for(const auto& i : bound_trait.m_type_bounds) {
+ // TODO: Only include from above when needed
+ //if( des_trait_ref.m_types.count(i.first) ) {
assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
- }
- for(const auto& i : e.trait.m_type_bounds) {
- // TODO: Only include from above when needed
- //if( des_trait_ref.m_types.count(i.first) ) {
- assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
- //}
- }
- return callback( ImplRef(ty.clone(), params.clone(), mv$(assoc2)), ::HIR::Compare::Equal );
- });
- if( rv ) {
- return true;
- }
+ //}
+ }
+ // TODO: Check param equality
+ auto ord = ::HIR::Compare::Equal;
+ ord &= this->compare_pp(sp, b_params, params);
+ if( ord == ::HIR::Compare::Unequal )
+ return false;
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
+ }
+ return callback( ImplRef(ty.clone(), b_params.clone(), mv$(assoc2)), ord );
+ });
+ if( rv ) {
+ return true;
}
+ }
- // If the input type is an associated type controlled by this trait bound, check for added bounds.
- // TODO: This just checks a single layer, but it's feasable that there could be multiple layers
- if( assoc_info && e.trait.m_path.m_path == assoc_info->trait.m_path && e.type == *assoc_info->type )
- {
- // Check the trait params
- auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params);
- if( ord == ::HIR::Compare::Fuzzy ) {
- //TODO(sp, "Handle fuzzy matches searching for associated type bounds");
- }
- else if( ord == ::HIR::Compare::Unequal ) {
- return false;
- }
- auto outer_ord = ord;
+ // If the input type is an associated type controlled by this trait bound, check for added bounds.
+ // TODO: This just checks a single layer, but it's feasable that there could be multiple layers
+ if( assoc_info && bound_trait.m_path.m_path == assoc_info->trait.m_path && bound_ty == *assoc_info->type )
+ {
+ // Check the trait params
+ auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params);
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ //TODO(sp, "Handle fuzzy matches searching for associated type bounds");
+ }
+ else if( ord == ::HIR::Compare::Unequal ) {
+ return false;
+ }
+ auto outer_ord = ord;
- const auto& trait_ref = *e.trait.m_trait_ptr;
- const auto& at = trait_ref.m_types.at(assoc_info->item);
- for(const auto& bound : at.m_trait_bounds) {
- if( bound.m_path.m_path == trait )
- {
- auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
- const auto& ge = gt.m_data.as_Generic();
- if( ge.binding == 0xFFFF ) {
- return *assoc_info->type;
- }
- else {
- if( ge.binding >= assoc_info->trait.m_params.m_types.size() )
- BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range");
- return assoc_info->trait.m_params.m_types[ge.binding];
- }
- };
-
- DEBUG("- Found an associated type bound for this trait via another bound");
- ::HIR::Compare ord = outer_ord;
- if( monomorphise_pathparams_needed(bound.m_path.m_params) ) {
- // TODO: Use a compare+callback method instead
- auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false);
- ord &= this->compare_pp(sp, b_params_mono, params);
+ const auto& trait_ref = *bound_trait.m_trait_ptr;
+ const auto& at = trait_ref.m_types.at(assoc_info->item);
+ for(const auto& bound : at.m_trait_bounds) {
+ if( bound.m_path.m_path == trait )
+ {
+ auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ return *assoc_info->type;
}
else {
- ord &= this->compare_pp(sp, bound.m_path.m_params, params);
- }
- if( ord == ::HIR::Compare::Unequal )
- return false;
- if( ord == ::HIR::Compare::Fuzzy ) {
- DEBUG("Fuzzy match");
+ if( ge.binding >= assoc_info->trait.m_params.m_types.size() )
+ BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range");
+ return assoc_info->trait.m_params.m_types[ge.binding];
}
+ };
- auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false);
- // - Expand associated types
- for(auto& ty : tp_mono.m_type_bounds) {
- ty.second = this->expand_associated_types(sp, mv$(ty.second));
- }
- DEBUG("- tp_mono = " << tp_mono);
- // TODO: Instead of using `type` here, build the real type
- if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) {
- return true;
- }
+ DEBUG("- Found an associated type bound for this trait via another bound");
+ ::HIR::Compare ord = outer_ord;
+ if( monomorphise_pathparams_needed(bound.m_path.m_params) ) {
+ // TODO: Use a compare+callback method instead
+ auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false);
+ ord &= this->compare_pp(sp, b_params_mono, params);
+ }
+ else {
+ ord &= this->compare_pp(sp, bound.m_path.m_params, params);
+ }
+ if( ord == ::HIR::Compare::Unequal )
+ return false;
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
+ }
+
+ auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false);
+ // - Expand associated types
+ for(auto& ty : tp_mono.m_type_bounds) {
+ ty.second = this->expand_associated_types(sp, mv$(ty.second));
+ }
+ DEBUG("- tp_mono = " << tp_mono);
+ // TODO: Instead of using `type` here, build the real type
+ if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) {
+ return true;
}
}
}
-
- return false;
}
+
return false;
});
}
@@ -2346,7 +2460,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
t_cb_trait_impl_r callback
) const
{
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
+ // TODO: Have a global cache of impls that don't reference either generics or ivars
+
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << "<?>"; }) << " for " << type);
// Handle auto traits (aka OIBITs)
@@ -2380,21 +2496,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
TU_IFLET( ::HIR::TypeRef::Data, (type.m_data), Path, e,
if( e.path.m_data.is_Generic() && e.path.m_data.as_Generic().m_params.m_types.size() == 0 )
{
- TU_MATCH( ::HIR::TypeRef::TypePathBinding, (e.binding), (tpb),
- (Unbound,
- ),
- (Opaque,
- ),
- (Struct,
- markings = &tpb->m_markings;
- ),
- (Union,
- markings = &tpb->m_markings;
- ),
- (Enum,
- markings = &tpb->m_markings;
- )
- )
+ markings = e.binding.get_trait_markings();
}
)
@@ -2491,7 +2593,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
if( cmp != ::HIR::Compare::Unequal )
{
if( markings ) {
- ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure");
+ ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure - " << trait << " for " << type);
markings->auto_impls.insert( ::std::make_pair(trait, ::HIR::TraitMarkings::AutoMarking { {}, true }) );
}
return callback( ImplRef(&type, params_ptr, &null_assoc), cmp );
@@ -2535,10 +2637,12 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
};
// - If the type is a path (struct/enum/...), search for impls for all contained types.
- TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Path, e,
+ if(const auto* ep = type.m_data.opt_Path())
+ {
+ const auto& e = *ep;
::HIR::Compare res = ::HIR::Compare::Equal;
- TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe),
- (Generic,
+ TU_MATCH_HDRA( (e.path.m_data), {)
+ TU_ARMA(Generic, pe) { //(
::HIR::TypeRef tmp;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
@@ -2557,7 +2661,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
// HELPER: Get a possibily monomorphised version of the input type (stored in `tmp` if needed)
auto monomorph_get = [&](const auto& ty)->const ::HIR::TypeRef& {
if( monomorphise_type_needed(ty) ) {
- return (tmp = monomorphise_type_with(sp, ty, monomorph_cb));
+ return (tmp = this->expand_associated_types(sp, monomorphise_type_with(sp, ty, monomorph_cb)));
}
else {
return ty;
@@ -2618,28 +2722,40 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
),
(Union,
TODO(sp, "Check auto trait destructure on union " << type);
+ ),
+ (ExternType,
+ TODO(sp, "Check auto trait destructure on extern type " << type);
)
)
DEBUG("- Nothing failed, calling callback");
- ),
- (UfcsUnknown,
+ }
+ TU_ARMA(UfcsUnknown, pe) {
BUG(sp, "UfcsUnknown in typeck - " << type);
- ),
- (UfcsKnown,
- // If unbound, use Fuzzy
- if(e.binding.is_Unbound())
+ }
+ TU_ARMA(UfcsKnown, pe) {
+ // If unbound, use Fuzzy {
+ if(e.binding.is_Unbound()) {
+ DEBUG("- Unbound UfcsKnown, returning Fuzzy");
return ::HIR::Compare::Fuzzy;
+ }
// Otherwise, it's opaque. Check the bounds on the trait.
+ if( TU_TEST1(pe.type->m_data, Generic, .binding >> 8 == 2) )
+ {
+ DEBUG("- UfcsKnown of placeholder, returning Fuzzy");
+ return ::HIR::Compare::Fuzzy;
+ }
TODO(sp, "Check trait bounds for bound on " << type);
- ),
- (UfcsInherent,
+ }
+ TU_ARMA(UfcsInherent, pe) {
TODO(sp, "Auto trait lookup on UFCS Inherent type");
- )
- )
+ }
+ }
return res;
- )
+ }
else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Generic, e,
- TODO(sp, "Check trait bounds on " << type);
+ auto l_res = ::HIR::Compare::Unequal;
+ this->find_trait_impls(sp, trait, *params_ptr, type, [&](auto, auto cmp){ l_res = cmp; return (cmp == ::HIR::Compare::Equal); });
+ return l_res;
)
else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Tuple, e,
::HIR::Compare res = ::HIR::Compare::Equal;
@@ -2714,7 +2830,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
// TODO: Some impl blocks have type params used as part of type bounds.
// - A rough idea is to have monomorph return a third class of generic for params that are not yet bound.
// - compare_with_placeholders gets called on both ivars and generics, so that can be used to replace it once known.
- ::std::string placeholder_name = FMT("impl_?_" << &impl_params);
+ auto placeholder_name = RcString::new_interned(FMT("impl_?_" << &impl_params));
for(unsigned int i = 0; i < impl_params.size(); i ++ ) {
if( !impl_params[i] ) {
if( placeholders.size() == 0 )
@@ -2761,6 +2877,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
auto i = idx % 256;
ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned - " << *impl_params[i] << " vs " << ty);
auto& ph = placeholders[i];
+ // TODO: Only want to do this if ... what?
+ // - Problem: This can poison the output if the result was fuzzy
+ // - E.g. `Q: Borrow<V>` can equate Q and V
if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
DEBUG("[ftic_check_params:cb_match] Bind placeholder " << i << " to " << ty);
ph = ty.clone();
@@ -2780,6 +2899,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;
}
};
@@ -2794,6 +2917,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
return *impl_params[ge.binding];
};
+ //::std::vector<::HIR::TypeRef> saved_ph;
+ //for(const auto& t : placeholders)
+ // saved_ph.push_back(t.clone());
// Check bounds for this impl
// - If a bound fails, then this can't be a valid impl
@@ -2805,6 +2931,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
(TypeLifetime,
),
(TraitBound,
+
DEBUG("Check bound " << be.type << " : " << be.trait);
auto real_type = monomorphise_type_with(sp, be.type, monomorph, false);
auto real_trait = monomorphise_traitpath_with(sp, be.trait, monomorph, false);
@@ -2828,8 +2955,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bounded type is an ivar, assuming fuzzy match");
found_fuzzy_match = true;
}
+ // TODO: Save the placeholder state and restore if the result was Fuzzy
+ ::std::vector<::HIR::TypeRef> saved_ph;
+ for(const auto& t : placeholders)
+ saved_ph.push_back(t.clone());
+ ::std::vector<::HIR::TypeRef> fuzzy_ph;
+ unsigned num_fuzzy = 0;
// TODO: Pass the `match_test_generics` callback? Or another one that handles the impl placeholders.
auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](auto impl, auto impl_cmp) {
+ // TODO: Save and restore placeholders if this isn't a full match
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", impl = " << impl);
auto cmp = impl_cmp;
if( cmp == ::HIR::Compare::Fuzzy )
@@ -2840,9 +2974,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
auto i_tp = impl.get_trait_params();
for(auto& t : i_tp.m_types)
this->expand_associated_types_inplace( sp, t, {} );
- DEBUG(real_type << " ?= " << i_ty);
+ DEBUG("[ftic_check_params] " << real_type << " ?= " << i_ty);
cmp &= real_type .match_test_generics_fuzz(sp, i_ty, cb_infer, cb_match);
- DEBUG(real_trait_path.m_params << " ?= " << i_tp);
+ DEBUG("[ftic_check_params] " << real_trait_path.m_params << " ?= " << i_tp);
cmp &= real_trait_path.m_params .match_test_generics_fuzz(sp, i_tp, cb_infer, cb_match);
DEBUG("[ftic_check_params] - Re-check result: " << cmp);
}
@@ -2872,22 +3006,41 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
{
case ::HIR::Compare::Equal:
DEBUG("Equal");
- continue;
+ break;
case ::HIR::Compare::Unequal:
DEBUG("Assoc `" << assoc_bound.first << "` didn't match - " << ty << " != " << assoc_bound.second);
- return false;
+ cmp = ::HIR::Compare::Unequal;
+ break;
case ::HIR::Compare::Fuzzy:
// TODO: When a fuzzy match is encountered on a conditional bound, returning `false` can lead to an false negative (and a compile error)
// BUT, returning `true` could lead to it being selected. (Is this a problem, should a later validation pass check?)
DEBUG("[ftic_check_params] Fuzzy match assoc bound between " << ty << " and " << assoc_bound.second);
cmp = ::HIR::Compare::Fuzzy;
- continue ;
+ break ;
}
+ if( cmp == ::HIR::Compare::Unequal )
+ break;
}
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", cmp = " << cmp);
- if( cmp == ::HIR::Compare::Fuzzy ) {
- found_fuzzy_match = true;
+ if( cmp == ::HIR::Compare::Fuzzy )
+ {
+ found_fuzzy_match |= true;
+ num_fuzzy += 1;
+ if( num_fuzzy )
+ {
+ fuzzy_ph = ::std::move(placeholders);
+ placeholders.resize(fuzzy_ph.size());
+ }
+ }
+ if( cmp != ::HIR::Compare::Equal )
+ {
+ // Restore placeholders
+ // - Maybe save the results for later?
+ DEBUG("[ftic_check_params] Restore placeholders: " << saved_ph);
+ DEBUG("[ftic_check_params] OVERWRITTEN placeholders: " << placeholders);
+ for(size_t i = 0; i < placeholders.size(); i ++)
+ placeholders[i] = saved_ph[i].clone();
}
// If the match isn't a concrete equal, return false (to keep searching)
return (cmp == ::HIR::Compare::Equal);
@@ -2897,6 +3050,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
else if( found_fuzzy_match ) {
DEBUG("- Bound " << real_type << " : " << real_trait_path << " fuzzed");
+ if( num_fuzzy == 1 )
+ {
+ DEBUG("Use placeholders " << fuzzy_ph);
+ placeholders = ::std::move(fuzzy_ph);
+ }
+ else
+ {
+ DEBUG("TODO: Multiple fuzzy matches, which placeholder set to use?");
+ }
match = ::HIR::Compare::Fuzzy;
}
else if( TU_TEST1(real_type.m_data, Infer, .ty_class == ::HIR::InferClass::None) ) {
@@ -2911,6 +3073,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bound " << real_type << " : " << real_trait_path << " failed");
return ::HIR::Compare::Unequal;
}
+
+ //if( !rv ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
),
(TypeEquality,
TODO(sp, "Check bound " << be.type << " = " << be.other_type);
@@ -2935,18 +3101,22 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
}
+ //if( match == ::HIR::Compare::Fuzzy ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
+
return match;
}
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 char* 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,29 +3124,32 @@ 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 char* 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
+bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const
{
TRACE_FUNCTION_FR(trait_path << " has " << name, out_path);
@@ -3038,6 +3211,10 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa
(Opaque,
// TODO: Check bounds
),
+ (ExternType,
+ // Is it sized? No.
+ return ::HIR::Compare::Unequal;
+ ),
(Enum,
// HAS to be Sized
),
@@ -3156,6 +3333,100 @@ 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;
+ ),
+ (Closure,
+ // NOTE: This isn't strictly true, we're leaving the actual checking up to the validate pass
+ return ::HIR::Compare::Equal;
+ ),
+ (Array,
+ return type_is_clone(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.
@@ -3444,12 +3715,16 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty
DEBUG("Deref " << ty << " into " << *e.inner);
return &this->m_ivars.get_type(*e.inner);
)
- // TODO: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work
+ // HACK?: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
DEBUG("Deref " << ty << " into [" << *e.inner << "]");
tmp_type = ::HIR::TypeRef::new_slice( e.inner->clone() );
return &tmp_type;
)
+ // Shortcut, don't look up a Deref impl for primitives or slices
+ else if( ty.m_data.is_Slice() || ty.m_data.is_Primitive() ) {
+ return nullptr;
+ }
else {
bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](auto impls, auto match) {
tmp_type = impls.get_type("Target");
@@ -3471,7 +3746,7 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty
}
unsigned int TraitResolution::autoderef_find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const char* method_name,
/* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const
{
@@ -3536,6 +3811,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp,
}
if( !possibilities.empty() )
{
+ DEBUG("FOUND " << possibilities.size() << " options: " << possibilities);
return deref_count;
}
@@ -3553,9 +3829,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp,
}
} while(current_ty);
- // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
- //this->m_ivars.dump();
- ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`");
+ // No method found, return an empty list and return 0
+ assert( possibilities.empty() );
+ return 0;
}
::std::ostream& operator<<(::std::ostream& os, const TraitResolution::AutoderefBorrow& x)
@@ -3594,9 +3870,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
@@ -3604,7 +3880,7 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H
case ::HIR::Function::Receiver::Value:
if( access >= TraitResolution::MethodAccess::Move )
{
- return &ty;
+ return &this->m_ivars.get_type(ty);
}
break;
case ::HIR::Function::Receiver::BorrowOwned:
@@ -3643,6 +3919,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 &this->m_ivars.get_type(*detected_self_ty);
+ }
+ }
+ return nullptr;
case ::HIR::Function::Receiver::Box:
if(const auto* ity = this->type_is_owned_box(sp, ty))
{
@@ -3660,12 +3954,12 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H
}
bool TraitResolution::find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access,
AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const
{
bool rv = false;
- TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name << ", access=" << access);
+ TRACE_FUNCTION_FR("ty=" << ty << ", name=" << method_name << ", access=" << access, possibilities);
auto cb_infer = m_ivars.callback_resolve_infer();
// 1. Search generic bounds for a match
@@ -3682,16 +3976,19 @@ 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 the type is an unbounded ivar, don't check.
+ if( TU_TEST1(self_ty->m_data, Infer, .is_lit() == false) )
+ 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 )
@@ -3707,12 +4004,23 @@ bool TraitResolution::find_method(const Span& sp,
method_name,
{}
}) ) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
- break;
}
else if( cmp == ::HIR::Compare::Fuzzy )
{
- TODO(sp, "Fuzzy match checking bounded method - " << *self_ty << " != " << e.type);
+ DEBUG("Fuzzy match checking bounded method - " << *self_ty << " != " << e.type);
+
+ // Found the method, return the UFCS path for it
+ possibilities.push_back(::std::make_pair( borrow_type,
+ ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
+ box$( self_ty->clone() ),
+ mv$(final_trait_path),
+ method_name,
+ {}
+ }) ) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
}
else
{
@@ -3760,17 +4068,23 @@ 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, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
+
+ // If the method was found on the trait object, prefer that over all others.
+ if( !possibilities.empty() )
+ {
+ return rv;
+ }
}
// 3. Mutually exclusive searches
@@ -3783,14 +4097,14 @@ 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, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
@@ -3835,21 +4149,23 @@ 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, {}) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
+ }
}
}
@@ -3873,21 +4189,22 @@ 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, {}) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
+ }
}
}
}
@@ -3907,12 +4224,13 @@ 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 )
{
possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
return true;
}
}
@@ -3943,12 +4261,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);
@@ -3965,10 +4283,24 @@ bool TraitResolution::find_method(const Span& sp,
// TODO: Re-monomorphise the trait path!
- //if( find_trait_impls(sp, *trait_ref.first, trait_params, self_ty, [](auto , auto ) { return true; }) ) {
- if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [](auto , auto ) { return true; }) ) {
+ bool magic_found = false;
+ bool crate_impl_found = false;
+
+ crate_impl_found = find_trait_impls_magic(sp, *trait_ref.first, trait_params, self_ty, [&](auto impl, auto cmp) {
+ return true;
+ });
+
+ // NOTE: This just detects the presence of a trait impl, not the specifics
+ find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [&](auto impl, auto cmp) {
+ DEBUG("[find_method] " << impl << ", cmp = " << cmp);
+ magic_found = true;
+ crate_impl_found = true;
+ return true;
+ });
+ if( crate_impl_found ) {
DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << self_ty << " ("<<m_ivars.fmt_type(self_ty)<<")");
possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty.clone(), ::HIR::GenericPath( *trait_ref.first, mv$(trait_params) ), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
@@ -3981,7 +4313,7 @@ bool TraitResolution::find_method(const Span& sp,
return rv;
}
-unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& field_name, /* Out -> */::HIR::TypeRef& field_type) const
+unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* field_name, /* Out -> */::HIR::TypeRef& field_type) const
{
unsigned int deref_count = 0;
::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
@@ -4021,7 +4353,7 @@ unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::
this->m_ivars.dump();
TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name);
}
-bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_ty) const
+bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_ty) const
{
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
@@ -4056,8 +4388,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Tuple,
for( unsigned int i = 0; i < se.size(); i ++ )
{
- // TODO: Privacy
- if( FMT(i) == name ) {
+ DEBUG(i << ": " << se[i].publicity);
+ if( se[i].publicity.is_visible(this->m_vis_path) && FMT(i) == name ) {
field_ty = monomorphise_type_with(sp, se[i].ent, monomorph);
return true;
}
@@ -4066,8 +4398,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Named,
for( const auto& fld : se )
{
- // TODO: Privacy
- if( fld.first == name ) {
+ DEBUG(fld.first << ": " << fld.second.publicity << ", " << this->m_vis_path);
+ if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) {
field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
return true;
}
@@ -4078,6 +4410,9 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Enum,
// No fields on enums either
),
+ (ExternType,
+ // No fields on extern types
+ ),
(Union,
const auto& unm = *be;
const auto& params = e.path.m_data.as_Generic().m_params;
@@ -4098,7 +4433,7 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
for( const auto& fld : unm.m_variants )
{
// TODO: Privacy
- if( fld.first == name ) {
+ if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) {
field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
return true;
}
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index 58688d6e..00befd63 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -57,6 +57,7 @@ public:
public: // ?? - Needed once, anymore?
struct IVar
{
+ //bool could_be_diverge; // TODO: use this instead of InferClass::Diverge
unsigned int alias; // If not ~0, this points to another ivar
::std::unique_ptr< ::HIR::TypeRef> type; // Type (only nullptr if alias!=0)
@@ -149,17 +150,19 @@ class TraitResolution
const ::HIR::Crate& m_crate;
const ::HIR::GenericParams* m_impl_params;
const ::HIR::GenericParams* m_item_params;
+ const ::HIR::SimplePath& m_vis_path;
::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities;
::HIR::SimplePath m_lang_Box;
mutable ::std::vector< ::HIR::TypeRef> m_eat_active_stack;
public:
- TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
+ TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& vis_path):
m_ivars(ivars),
m_crate(crate),
m_impl_params( impl_params ),
m_item_params( item_params )
+ ,m_vis_path(vis_path)
{
prep_indexes();
m_lang_Box = crate.get_lang_item_path_opt("owned_box");
@@ -201,13 +204,14 @@ public:
/// Iterate over in-scope bounds (function then top)
bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const;
+ bool iterate_bounds_traits(const Span& sp, ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::TraitPath& trait)> cb) const;
bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const;
- typedef ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl;
+ typedef ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::PathParams&, const ::std::map< RcString,::HIR::TypeRef>&)> t_cb_trait_impl;
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,
@@ -224,6 +228,8 @@ public:
}
/// Search for a trait implementation in the crate (allows nullptr to ignore params)
bool find_trait_impls_crate(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const;
+ /// Check for magic (automatically determined) trait implementations
+ bool find_trait_impls_magic(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const;
private:
::HIR::Compare check_auto_trait_impl_destructure(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params_ptr, const ::HIR::TypeRef& type) const;
@@ -244,17 +250,17 @@ public:
/// Locate the named method by applying auto-dereferencing.
/// \return Number of times deref was applied (or ~0 if _ was hit)
unsigned int autoderef_find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const char* method_name,
/* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const;
/// Locate the named field by applying auto-dereferencing.
/// \return Number of times deref was applied (or ~0 if _ was hit)
- unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
+ unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const;
/// Apply an automatic dereference
const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const;
- bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
+ bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const;
enum class MethodAccess {
Shared,
@@ -262,7 +268,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,
@@ -273,16 +279,17 @@ public:
};
friend ::std::ostream& operator<<(::std::ostream& os, const AllowedReceivers& x);
bool find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access,
AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) 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;
- 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;
+ const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const char* name, ::HIR::GenericPath& out_path) const;
+ bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* 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/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp
index e8966b38..910a3c5e 100644
--- a/src/hir_typeck/impl_ref.cpp
+++ b/src/hir_typeck/impl_ref.cpp
@@ -32,10 +32,24 @@ bool ImplRef::more_specific_than(const ImplRef& other) const
)
),
(BoundedPtr,
- return true;
+ if( !other.m_data.is_BoundedPtr() )
+ return false;
+ const auto& oe = other.m_data.as_BoundedPtr();
+ assert( *te.type == *oe.type );
+ assert( *te.trait_args == *oe.trait_args );
+ if( te.assoc->size() > oe.assoc->size() )
+ return true;
+ return false;
),
(Bounded,
- return true;
+ if( !other.m_data.is_Bounded() )
+ return false;
+ const auto& oe = other.m_data.as_Bounded();
+ assert( te.type == oe.type );
+ assert( te.trait_args == oe.trait_args );
+ if( te.assoc.size() > oe.assoc.size() )
+ return true;
+ return false;
)
)
throw "";
@@ -50,12 +64,34 @@ bool ImplRef::overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) con
return te.impl->overlaps_with( crate, *oe.impl );
),
(BoundedPtr,
+ // TODO: Bounded and BoundedPtr are compatible
+ if( *te.type != *oe.type )
+ return false;
+ if( *te.trait_args != *oe.trait_args )
+ return false;
+ // Don't check associated types
+ return true;
),
(Bounded,
+ if( te.type != oe.type )
+ return false;
+ if( te.trait_args != oe.trait_args )
+ return false;
+ // Don't check associated types
+ return true;
)
)
return false;
}
+bool ImplRef::has_magic_params() const
+{
+ TU_IFLET(Data, m_data, TraitImpl, e,
+ for(const auto& t : e.params_ph)
+ if( visit_ty_with(t, [](const ::HIR::TypeRef& t){ return t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2; }) )
+ return true;
+ )
+ return false;
+}
bool ImplRef::type_is_specialisable(const char* name) const
{
TU_MATCH(Data, (this->m_data), (e),
@@ -189,11 +225,11 @@ bool ImplRef::type_is_specialisable(const char* name) const
static Span sp;
TU_MATCH(Data, (this->m_data), (e),
(TraitImpl,
- DEBUG("name=" << name << " " << *this);
auto it = e.impl->m_types.find(name);
if( it == e.impl->m_types.end() )
return ::HIR::TypeRef();
const ::HIR::TypeRef& tpl_ty = it->second.data;
+ DEBUG("name=" << name << " tpl_ty=" << tpl_ty << " " << *this);
if( monomorphise_type_needed(tpl_ty) ) {
return monomorphise_type_with(sp, tpl_ty, this->get_cb_monomorph_traitimpl(sp));
}
@@ -219,8 +255,8 @@ bool ImplRef::type_is_specialisable(const char* name) const
::std::ostream& operator<<(::std::ostream& os, const ImplRef& x)
{
- TU_MATCH(ImplRef::Data, (x.m_data), (e),
- (TraitImpl,
+ TU_MATCH_HDR( (x.m_data), { )
+ TU_ARM(x.m_data, TraitImpl, e) {
if( e.impl == nullptr ) {
os << "none";
}
@@ -258,13 +294,16 @@ bool ImplRef::type_is_specialisable(const char* name) const
}
os << "}";
}
- ),
- (BoundedPtr,
+ }
+ TU_ARM(x.m_data, BoundedPtr, e) {
+ assert(e.type);
+ assert(e.trait_args);
+ assert(e.assoc);
os << "bound (ptr) " << *e.type << " : ?" << *e.trait_args << " + {" << *e.assoc << "}";
- ),
- (Bounded,
+ }
+ TU_ARM(x.m_data, Bounded, e) {
os << "bound " << e.type << " : ?" << e.trait_args << " + {"<<e.assoc<<"}";
- )
- )
+ }
+ }
return os;
}
diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp
index b1190c61..c67c8a81 100644
--- a/src/hir_typeck/impl_ref.hpp
+++ b/src/hir_typeck/impl_ref.hpp
@@ -27,12 +27,12 @@ struct ImplRef
(BoundedPtr, struct {
const ::HIR::TypeRef* type;
const ::HIR::PathParams* trait_args;
- const ::std::map< ::std::string, ::HIR::TypeRef>* assoc;
+ const ::std::map< RcString, ::HIR::TypeRef>* assoc;
}),
(Bounded, struct {
::HIR::TypeRef type;
::HIR::PathParams trait_args;
- ::std::map< ::std::string, ::HIR::TypeRef> assoc;
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
})
);
@@ -45,10 +45,10 @@ struct ImplRef
m_data(Data::make_TraitImpl({ mv$(params), mv$(params_ph), &trait, &impl }))
{}
- ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< ::std::string, ::HIR::TypeRef>* assoc):
+ ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< RcString, ::HIR::TypeRef>* assoc):
m_data(Data::make_BoundedPtr({ type, mv$(args), mv$(assoc) }))
{}
- ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< ::std::string, ::HIR::TypeRef> assoc):
+ ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< RcString, ::HIR::TypeRef> assoc):
m_data(Data::make_Bounded({ mv$(type), mv$(args), mv$(assoc) }))
{}
@@ -59,14 +59,7 @@ struct ImplRef
bool more_specific_than(const ImplRef& other) const;
bool overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) const;
- bool has_magic_params() const {
- TU_IFLET(Data, m_data, TraitImpl, e,
- for(const auto& t : e.params_ph)
- if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 )
- return true;
- )
- return false;
- }
+ bool has_magic_params() const;
/// HELPER: Returns callback to monomorphise a type using parameters from Data::TraitImpl
::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> get_cb_monomorph_traitimpl(const Span& sp) const;
diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp
index dddb7731..38c6f652 100644
--- a/src/hir_typeck/outer.cpp
+++ b/src/hir_typeck/outer.cpp
@@ -52,6 +52,10 @@ namespace {
(TypeAlias,
BUG(sp, "Type path pointed to type alias - " << path);
),
+ (ExternType,
+ static ::HIR::GenericParams empty_params;
+ return empty_params;
+ ),
(Module,
BUG(sp, "Type path pointed to module - " << path);
),
@@ -201,13 +205,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 +227,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]);
}
@@ -288,24 +295,53 @@ namespace {
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, ErasedType, e,
if( e.m_origin == ::HIR::SimplePath() )
{
- // If not, ensure taht we're checking a function return type, and error if not
- if( ! m_fcn_path )
+ // If not, figure out what to do with it
+
+ // If the function path is set, we're processing the return type of a function
+ // - Add this to the list of erased types associated with the function
+ if( m_fcn_path )
+ {
+ assert(m_fcn_ptr);
+ DEBUG(*m_fcn_path << " " << m_fcn_erased_count);
+
+ ::HIR::PathParams params;
+ for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++)
+ params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i));
+ // Populate with function path
+ e.m_origin = m_fcn_path->get_full_path();
+ TU_MATCHA( (e.m_origin.m_data), (e2),
+ (Generic, e2.m_params = mv$(params); ),
+ (UfcsInherent, e2.params = mv$(params); ),
+ (UfcsKnown, e2.params = mv$(params); ),
+ (UfcsUnknown, throw ""; )
+ )
+ e.m_index = m_fcn_erased_count++;
+ }
+ // If the function _pointer_ is set (but not the path), then we're in the function arguments
+ // - Add a un-namable generic parameter (TODO: Prevent this from being explicitly set when called)
+ else if( m_fcn_ptr )
+ {
+ size_t idx = m_fcn_ptr->m_params.m_types.size();
+ auto name = RcString::new_interned(FMT("impl$" << idx));
+ auto new_ty = ::HIR::TypeRef( name, 256 + idx );
+ m_fcn_ptr->m_params.m_types.push_back({ name, ::HIR::TypeRef(), true });
+ for( const auto& trait : e.m_traits )
+ {
+ m_fcn_ptr->m_params.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({
+ new_ty.clone(),
+ trait.clone()
+ }));
+ }
+ if( e.m_lifetime != ::HIR::LifetimeRef() )
+ {
+ TODO(sp, "Add bound " << new_ty << " : " << e.m_lifetime);
+ }
+ ty = ::std::move(new_ty);
+ }
+ else
+ {
ERROR(sp, E0000, "Use of an erased type outside of a function return - " << ty);
- assert(m_fcn_ptr);
- DEBUG(*m_fcn_path << " " << m_fcn_erased_count);
-
- ::HIR::PathParams params;
- for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++)
- params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i));
- // Populate with function path
- e.m_origin = m_fcn_path->get_full_path();
- TU_MATCHA( (e.m_origin.m_data), (e2),
- (Generic, e2.m_params = mv$(params); ),
- (UfcsInherent, e2.params = mv$(params); ),
- (UfcsKnown, e2.params = mv$(params); ),
- (UfcsUnknown, throw ""; )
- )
- e.m_index = m_fcn_erased_count++;
+ }
}
)
}
@@ -429,6 +465,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 +495,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 ;
@@ -463,26 +506,25 @@ namespace {
)
else {
// 1. Search for applicable inherent methods (COMES FIRST!)
- for( const auto& impl : this->crate.m_type_impls )
- {
- if( !impl.matches_type(*e.type) ) {
- continue ;
- }
+ if( this->crate.find_type_impls(*e.type, [](const auto& ty)->const auto&{return ty;}, [&](const auto& impl) {
DEBUG("- matched inherent impl " << *e.type);
// Search for item in this block
switch( pc )
{
case ::HIR::Visitor::PathContext::VALUE:
if( impl.m_methods.find(e.item) == impl.m_methods.end() ) {
- continue ;
+ return false;
}
// Found it, just keep going (don't care about details here)
break;
case ::HIR::Visitor::PathContext::TRAIT:
case ::HIR::Visitor::PathContext::TYPE:
- continue ;
+ return false;
}
+ return true;
+ }) )
+ {
auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} );
p.m_data = mv$(new_data);
DEBUG("- Resolved, replace with " << p);
@@ -616,6 +658,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
{
@@ -661,6 +714,12 @@ namespace {
m_fcn_erased_count = 0;
visit_type(item.m_return);
m_fcn_path = nullptr;
+ // TODO: Visit arguments
+ for(auto& arg : item.m_args)
+ {
+ visit_type(arg.second);
+ }
+ m_fcn_ptr = nullptr;
::HIR::Visitor::visit_function(p, item);
}
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp
index 8000f5af..51e4b831 100644
--- a/src/hir_typeck/static.cpp
+++ b/src/hir_typeck/static.cpp
@@ -7,6 +7,7 @@
*/
#include "static.hpp"
#include <algorithm>
+#include <hir/expr.hpp>
void StaticTraitResolve::prep_indexes()
{
@@ -96,7 +97,7 @@ bool StaticTraitResolve::find_impl(
auto cb_ident = [](const ::HIR::TypeRef&ty)->const ::HIR::TypeRef& { return ty; };
static ::HIR::PathParams null_params;
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
if( !dont_handoff_to_specialised ) {
if( trait_path == m_lang_Copy ) {
@@ -104,6 +105,16 @@ bool StaticTraitResolve::find_impl(
return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
}
}
+ else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) {
+ // NOTE: Duplicated check for enumerate
+ if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() || type.m_data.is_Closure()
+ || TU_TEST1(type.m_data, Path, .is_closure()) )
+ {
+ 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 +129,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,
@@ -139,11 +160,52 @@ bool StaticTraitResolve::find_impl(
{
trait_params = &null_params;
}
- ::std::map< ::std::string, ::HIR::TypeRef> assoc;
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
assoc.insert( ::std::make_pair("Output", e.m_rettype->clone()) );
return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false );
}
)
+ if(const auto* e = type.m_data.opt_Closure())
+ {
+ if( trait_path == m_lang_Fn || trait_path == m_lang_FnMut || trait_path == m_lang_FnOnce )
+ {
+ if( trait_params )
+ {
+ const auto& des_arg_tys = trait_params->m_types.at(0).m_data.as_Tuple();
+ if( des_arg_tys.size() != e->m_arg_types.size() ) {
+ return false;
+ }
+ for(unsigned int i = 0; i < des_arg_tys.size(); i ++)
+ {
+ if( des_arg_tys[i] != e->m_arg_types[i] ) {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ trait_params = &null_params;
+ }
+ switch( e->node->m_class )
+ {
+ case ::HIR::ExprNode_Closure::Class::Unknown:
+ break;
+ case ::HIR::ExprNode_Closure::Class::NoCapture:
+ break;
+ case ::HIR::ExprNode_Closure::Class::Once:
+ if( trait_path == m_lang_FnMut )
+ return false;
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ if( trait_path == m_lang_Fn )
+ return false;
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ break;
+ }
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
+ assoc.insert( ::std::make_pair("Output", e->m_rettype->clone()) );
+ return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false );
+ }
+ }
// ----
// TraitObject traits and supertraits
@@ -162,7 +224,7 @@ bool StaticTraitResolve::find_impl(
if( trait_path == mt.m_path ) {
if( !trait_params || mt.m_params == *trait_params )
{
- static ::std::map< ::std::string, ::HIR::TypeRef> types;
+ static ::std::map< RcString, ::HIR::TypeRef> types;
return found_cb( ImplRef(&type, &mt.m_params, &types), false );
}
}
@@ -174,7 +236,7 @@ bool StaticTraitResolve::find_impl(
bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *e.m_trait.m_trait_ptr, e.m_trait.m_path.m_path,e.m_trait.m_path.m_params, type,
[&](const auto& i_params, const auto& i_assoc) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map< RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
// HACK! Just add all the associated type bounds (only inserted if not already present)
@@ -204,7 +266,7 @@ bool StaticTraitResolve::find_impl(
bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *trait.m_trait_ptr, trait.m_path.m_path,trait.m_path.m_params, type,
[&](const auto& i_params, const auto& i_assoc) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map< RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
// HACK! Just add all the associated type bounds (only inserted if not already present)
@@ -251,7 +313,7 @@ bool StaticTraitResolve::find_impl(
{
if( &b_params_mono == &params_mono_o || ::std::any_of(bound.m_type_bounds.begin(), bound.m_type_bounds.end(), [&](const auto& x){ return monomorphise_type_needed(x.second); }) )
{
- ::std::map< ::std::string, ::HIR::TypeRef> atys;
+ ::std::map< RcString, ::HIR::TypeRef> atys;
if( ! bound.m_type_bounds.empty() )
{
for(const auto& tb : bound.m_type_bounds)
@@ -416,7 +478,9 @@ bool StaticTraitResolve::find_impl__check_bound(
static bool compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) {
ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" );
for(unsigned int i = 0; i < left.m_types.size(); i ++) {
- if( left.m_types[i] != right.m_types[i] ) {
+ // TODO: Permits fuzzy comparison to handle placeholder params, should instead do a match/test/assign
+ if( left.m_types[i].compare_with_placeholders(sp, right.m_types[i], [](const auto&t)->const ::HIR::TypeRef&{return t;}) == ::HIR::Compare::Unequal ) {
+ //if( left.m_types[i] != right.m_types[i] ) {
return false;
}
}
@@ -521,6 +585,8 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
auto cb_ident = [](const auto&ty)->const ::HIR::TypeRef&{return ty;};
TRACE_FUNCTION_F("impl" << impl_params_def.fmt_args() << " " << des_trait_path << impl_trait_params << " for " << impl_type << impl_params_def.fmt_bounds());
+ // TODO: What if `des_trait_params` already has impl placeholders?
+
::std::vector< const ::HIR::TypeRef*> impl_params;
impl_params.resize( impl_params_def.m_types.size() );
@@ -528,6 +594,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
assert( idx < impl_params.size() );
if( ! impl_params[idx] ) {
impl_params[idx] = &ty;
+ DEBUG("[find_impl__check_crate_raw:cb] Set placeholder " << idx << " to " << ty);
return ::HIR::Compare::Equal;
}
else {
@@ -535,15 +602,34 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
}
};
auto match = impl_type.match_test_generics_fuzz(sp, des_type, cb_ident, cb);
+ unsigned base_impl_placeholder_idx = 0;
if( des_trait_params )
{
assert( des_trait_params->m_types.size() == impl_trait_params.m_types.size() );
+ unsigned max_impl_idx = 0;
for( unsigned int i = 0; i < impl_trait_params.m_types.size(); i ++ )
{
const auto& l = impl_trait_params.m_types[i];
const auto& r = des_trait_params->m_types[i];
match &= l.match_test_generics_fuzz(sp, r, cb_ident, cb);
+
+ visit_ty_with(r, [&](const ::HIR::TypeRef& t)->bool {
+ if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 ) {
+ unsigned impl_idx = t.m_data.as_Generic().binding & 0xFF;
+ max_impl_idx = ::std::max(max_impl_idx, impl_idx+1);
+ }
+ return false;
+ });
}
+ base_impl_placeholder_idx = max_impl_idx;
+
+ size_t n_placeholders_needed = 0;
+ for(unsigned int i = 0; i < impl_params.size(); i ++ ) {
+ if( !impl_params[i] ) {
+ n_placeholders_needed ++;
+ }
+ }
+ ASSERT_BUG(sp, base_impl_placeholder_idx + n_placeholders_needed <= 256, "Out of impl placeholders");
}
if( match == ::HIR::Compare::Unequal ) {
DEBUG(" > Type mismatch");
@@ -555,7 +641,8 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
if( !impl_params[i] ) {
if( placeholders.size() == 0 )
placeholders.resize(impl_params.size());
- placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i);
+ placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i + base_impl_placeholder_idx);
+ DEBUG("Placeholder " << placeholders[i] << " for " << impl_params_def.m_types[i].m_name);
}
}
// Callback that matches placeholders to concrete types
@@ -563,16 +650,24 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx )
return ::HIR::Compare::Equal;
if( idx >> 8 == 2 ) {
- auto i = idx % 256;
- ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned");
- auto& ph = placeholders[i];
- if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
- DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty);
- ph = ty.clone();
- return ::HIR::Compare::Equal;
+ if( (idx % 256) >= base_impl_placeholder_idx ) {
+ auto i = idx % 256 - base_impl_placeholder_idx;
+ ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned. new " << ty << ", existing " << *impl_params[i]);
+ auto& ph = placeholders[i];
+ if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
+ DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty);
+ 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);
+ }
}
else {
- TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty);
+ return ::HIR::Compare::Fuzzy;
}
}
else {
@@ -628,7 +723,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
const ::HIR::TypeRef& exp = assoc_bound.second;
::HIR::GenericPath aty_src_trait;
- trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name, aty_src_trait);
+ trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name.c_str(), aty_src_trait);
bool rv = false;
if( b_ty_mono.m_data.is_Generic() && (b_ty_mono.m_data.as_Generic().binding >> 8) == 2 ) {
@@ -640,6 +735,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
::HIR::TypeRef have = impl.get_type(aty_name.c_str());
this->expand_associated_types(sp, have);
+ DEBUG("::" << aty_name << " - " << have << " ?= " << exp);
//auto cmp = have .match_test_generics_fuzz(sp, exp, cb_ident, cb_match);
auto cmp = exp .match_test_generics_fuzz(sp, have, cb_ident, cb_match);
if( cmp == ::HIR::Compare::Unequal )
@@ -648,7 +744,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
});
}
if( !rv ) {
- DEBUG("> Fail (assoc) - " << b_ty_mono << " : " << aty_src_trait);
+ DEBUG("> Fail (assoc " << aty_name << ") - " << b_ty_mono << " : " << aty_src_trait);
return false;
}
}
@@ -799,6 +895,9 @@ bool StaticTraitResolve::find_impl__check_crate(
),
(Union,
TODO(sp, "Check auto trait destructure on union " << type);
+ ),
+ (ExternType,
+ TODO(sp, "Check auto trait destructure on extern type " << type);
)
)
DEBUG("- Nothing failed, calling callback");
@@ -924,6 +1023,9 @@ void StaticTraitResolve::expand_associated_types_inner(const Span& sp, ::HIR::Ty
),
(Closure,
// Recurse?
+ for(auto& ty : e.m_arg_types)
+ expand_associated_types_inner(sp, ty);
+ expand_associated_types_inner(sp, *e.m_rettype);
)
)
}
@@ -1143,7 +1245,7 @@ bool StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI
// - Search for the actual trait containing this associated type
::HIR::GenericPath trait_path;
- if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) )
+ if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait);
//e2.trait = mv$(trait_path);
@@ -1284,7 +1386,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp,
const ::HIR::SimplePath& des, const ::HIR::PathParams& des_params,
const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
const ::HIR::TypeRef& target_type,
- ::std::function<void(const ::HIR::PathParams&, ::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ::std::function<void(const ::HIR::PathParams&, ::std::map<RcString, ::HIR::TypeRef>)> callback
) const
{
TRACE_FUNCTION_F(des << des_params << " from " << trait_path << pp);
@@ -1309,16 +1411,23 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp,
auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false);
DEBUG(pt << " => " << pt_mono);
- if( pt.m_path.m_path == des && pt_mono.m_path.m_params == des_params )
+ // TODO: When in pre-typecheck mode, this needs to be a fuzzy match (because there might be a UfcsUnknown in the
+ // monomorphed version) OR, there may be placeholders
+ if( pt.m_path.m_path == des )
{
- callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) );
- return true;
+ auto cmp = pt_mono.m_path.m_params.compare_with_placeholders(sp, des_params, [](const auto& t)->const ::HIR::TypeRef&{return t;});
+ // pt_mono.m_path.m_params == des_params )
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) );
+ return true;
+ }
}
}
return false;
}
-bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const
+bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const
{
TRACE_FUNCTION_FR("name="<<name << ", trait=" << trait_path, out_path);
auto it = trait_ptr.m_types.find(name);
@@ -1364,6 +1473,13 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
return rv;
),
(Path,
+ const auto* markings = e.binding.get_trait_markings();
+ if( markings && ! markings->is_copy )
+ {
+ return false;
+ }
+ // TODO: Also have a marking that indicates that the type is unconditionally Copy
+
{
auto it = m_copy_cache.find(ty);
if( it != m_copy_cache.end() )
@@ -1379,6 +1495,11 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
return true;
),
(Closure,
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Auto-gerated impls
+ return e.node->m_is_copy;
+ }
return false;
),
(Infer,
@@ -1430,101 +1551,99 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
)
throw "";
}
-
-bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const
+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,
- if( e.binding == 0xFFFF ) {
- // TODO: Self: Sized?
- return true;
- }
- else if( (e.binding >> 8) == 0 ) {
- auto idx = e.binding & 0xFF;
- assert( m_impl_generics );
- assert( idx < m_impl_generics->m_types.size() );
- return m_impl_generics->m_types[idx].m_is_sized;
- }
- else if( (e.binding >> 8) == 1 ) {
- auto idx = e.binding & 0xFF;
- assert( m_item_generics );
- assert( idx < m_item_generics->m_types.size() );
- return m_item_generics->m_types[idx].m_is_sized;
- }
- else {
- BUG(sp, "");
+ {
+ 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,
- TU_MATCHA( (e.binding), (pbe),
- (Unbound,
- ),
- (Opaque,
- //auto pp = ::HIR::PathParams();
- //return this->find_impl(sp, m_lang_Sized, &pp, ty, [&](auto , bool){ return true; }, true);
- // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
- return true;
- ),
- (Struct,
- // TODO: Destructure?
- switch( pbe->m_struct_markings.dst_type )
- {
- case ::HIR::StructMarkings::DstType::None:
- return true;
- case ::HIR::StructMarkings::DstType::Possible:
- return type_is_sized( sp, e.path.m_data.as_Generic().m_params.m_types.at(pbe->m_struct_markings.unsized_param) );
- case ::HIR::StructMarkings::DstType::Slice:
- case ::HIR::StructMarkings::DstType::TraitObject:
- return false;
- }
- ),
- (Enum,
- ),
- (Union,
- )
- )
- return true;
+ if(true) {
+ auto it = m_clone_cache.find(ty);
+ if( it != m_clone_cache.end() )
+ return it->second;
+ }
+ if( e.is_closure() )
+ {
+ bool rv = true;
+ // TODO: Check all captures
+ m_clone_cache.insert(::std::make_pair( ty.clone(), rv ));
+ return rv;
+ }
+ 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 ...
+ // The ! type is kinda Copy/Clone ...
return true;
),
(Closure,
- return true;
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Auto-gerated impls
+ return e.node->m_is_copy;
+ }
+ return false;
),
(Infer,
// Shouldn't be hit
return false;
),
(Borrow,
- return true;
+ // 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 Sized
+ // All primitives (except the unsized `str`) are Copy/Clone
return e != ::HIR::CoreType::Str;
),
(Array,
- return true;
+ 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,
- // NOTE: All erased types are implicitly Sized
- return true;
+ 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_sized(sp, ty) )
+ if( !type_is_clone(sp, ty) )
return false;
return true;
)
@@ -1532,6 +1651,100 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty)
throw "";
}
+bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const
+{
+ switch( this->metadata_type(sp, ty) )
+ {
+ case MetadataType::None:
+ return true;
+ default:
+ return false;
+ }
+}
+bool StaticTraitResolve::type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const
+{
+ TU_MATCH_HDRA( (ty.m_data), {)
+ break;
+ default:
+ return false;
+ TU_ARMA(Diverge, _e)
+ return true;
+ TU_ARMA(Path, e) {
+ TU_MATCHA( (e.binding), (pbe),
+ (Unbound,
+ // BUG?
+ return false;
+ ),
+ (Opaque,
+ // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
+ return false;
+ ),
+ (Struct,
+ const auto& params = e.path.m_data.as_Generic().m_params;
+ // TODO: Check all fields, if one flags this, then it's impossible.
+ const auto& str = *pbe;
+ TU_MATCH_HDRA( (str.m_data), {)
+ TU_ARMA(Unit, e)
+ return false;
+ TU_ARMA(Tuple, e) {
+ for(const auto& fld : e)
+ {
+ const auto& tpl = fld.ent;
+ ::HIR::TypeRef tmp;
+ const auto& ty = (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, monomorphise_type_get_cb(sp, nullptr, &params, nullptr)) : tpl);
+ if( type_is_impossible(sp, ty) )
+ return true;
+ }
+ return false;
+ }
+ TU_ARMA(Named, e)
+ for(const auto& fld : e)
+ {
+ TODO(sp, "type_is_impossible for struct " << ty << " - " << fld.second.ent);
+ }
+ }
+ ),
+ (Enum,
+ // TODO: Check all variants.
+ TODO(sp, "type_is_impossible for enum " << ty);
+ ),
+ (Union,
+ // TODO: Check all variants? Or just one?
+ TODO(sp, "type_is_impossible for union " << ty);
+ ),
+ (ExternType,
+ // Extern types are possible, just not usable
+ return false;
+ )
+ )
+ return true;
+ }
+ TU_ARMA(Borrow, e)
+ return type_is_impossible(sp, *e.inner);
+ TU_ARMA(Pointer, e) {
+ return false;
+ //return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Function, e) {
+ // TODO: Check all arguments?
+ return true;
+ }
+ TU_ARMA(Array, e) {
+ return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Slice, e) {
+ return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Tuple, e) {
+ for(const auto& ty : e)
+ if( type_is_impossible(sp, ty) )
+ return true;
+ return false;
+ }
+ }
+ throw "";
+}
+
bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const
{
TRACE_FUNCTION_F(dst_ty << " <- " << src_ty);
@@ -1717,7 +1930,133 @@ bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty
DEBUG("Can't unsize, no rules matched");
return false;
+}
+MetadataType StaticTraitResolve::metadata_type(const Span& sp, const ::HIR::TypeRef& ty, bool err_on_unknown/*=false*/) const
+{
+ TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e),
+ (Generic,
+ if( e.binding == 0xFFFF ) {
+ // TODO: Self: Sized?
+ return MetadataType::None;
+ }
+ else if( (e.binding >> 8) == 0 ) {
+ auto idx = e.binding & 0xFF;
+ assert( m_impl_generics );
+ assert( idx < m_impl_generics->m_types.size() );
+ if( m_impl_generics->m_types[idx].m_is_sized ) {
+ return MetadataType::None;
+ }
+ else {
+ return MetadataType::Unknown;
+ }
+ }
+ else if( (e.binding >> 8) == 1 ) {
+ auto idx = e.binding & 0xFF;
+ assert( m_item_generics );
+ assert( idx < m_item_generics->m_types.size() );
+ if( m_item_generics->m_types[idx].m_is_sized ) {
+ return MetadataType::None;
+ }
+ else {
+ return MetadataType::Unknown;
+ }
+ }
+ else {
+ BUG(sp, "Unknown generic binding on " << ty);
+ }
+ ),
+ (Path,
+ TU_MATCHA( (e.binding), (pbe),
+ (Unbound,
+ // TODO: Should this return something else?
+ return MetadataType::Unknown;
+ ),
+ (Opaque,
+ //auto pp = ::HIR::PathParams();
+ //return this->find_impl(sp, m_lang_Sized, &pp, ty, [&](auto , bool){ return true; }, true);
+ // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
+ //return MetadataType::Unknown;
+ return MetadataType::None;
+ ),
+ (Struct,
+ // TODO: Destructure?
+ switch( pbe->m_struct_markings.dst_type )
+ {
+ case ::HIR::StructMarkings::DstType::None:
+ return MetadataType::None;
+ case ::HIR::StructMarkings::DstType::Possible:
+ return this->metadata_type( sp, e.path.m_data.as_Generic().m_params.m_types.at(pbe->m_struct_markings.unsized_param) );
+ case ::HIR::StructMarkings::DstType::Slice:
+ return MetadataType::Slice;
+ case ::HIR::StructMarkings::DstType::TraitObject:
+ return MetadataType::TraitObject;
+ }
+ ),
+ (ExternType,
+ // Extern types aren't Sized, but have no metadata
+ return MetadataType::Zero;
+ ),
+ (Enum,
+ ),
+ (Union,
+ )
+ )
+ return MetadataType::None;
+ ),
+ (Diverge,
+ // The ! type is kinda Sized ...
+ return MetadataType::None;
+ ),
+ (Closure,
+ return MetadataType::None;
+ ),
+ (Infer,
+ // Shouldn't be hit
+ BUG(sp, "Found ivar? " << ty);
+ ),
+ (Borrow,
+ return MetadataType::None;
+ ),
+ (Pointer,
+ return MetadataType::None;
+ ),
+ (Function,
+ return MetadataType::None;
+ ),
+ (Primitive,
+ // All primitives (except the unsized `str`) are Sized
+ if( e == ::HIR::CoreType::Str )
+ {
+ return MetadataType::Slice;
+ }
+ else
+ {
+ return MetadataType::None;
+ }
+ ),
+ (Array,
+ return MetadataType::None;
+ ),
+ (Slice,
+ return MetadataType::Slice;
+ ),
+ (TraitObject,
+ return MetadataType::TraitObject;
+ ),
+ (ErasedType,
+ // NOTE: All erased types are implicitly Sized
+ return MetadataType::None;
+ ),
+ (Tuple,
+ // TODO: Unsized tuples? are they a thing?
+ //for(const auto& ty : e)
+ // if( !type_is_sized(sp, ty) )
+ // return false;
+ return MetadataType::None;
+ )
+ )
+ throw "bug";
}
bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const
@@ -1735,10 +2074,25 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
if( e.binding.is_Opaque() )
return true;
+ // In 1.29, "manually_drop" is a struct with special behaviour (instead of being a union)
+ if( TARGETVER_1_29 && e.path.m_data.as_Generic().m_path == m_crate.get_lang_item_path_opt("manually_drop") )
+ {
+ return false;
+ }
+
+ auto it = m_drop_cache.find(ty);
+ if( it != m_drop_cache.end() )
+ {
+ return it->second;
+ }
+
auto pp = ::HIR::PathParams();
bool has_direct_drop = this->find_impl(sp, m_lang_Drop, &pp, ty, [&](auto , bool){ return true; }, true);
if( has_direct_drop )
+ {
+ m_drop_cache.insert(::std::make_pair(ty.clone(), true));
return true;
+ }
::HIR::TypeRef tmp_ty;
const auto& pe = e.path.m_data.as_Generic();
@@ -1753,6 +2107,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
return tpl;
}
};
+ bool needs_drop_glue = false;
TU_MATCHA( (e.binding), (pbe),
(Unbound,
BUG(sp, "Unbound path");
@@ -1769,18 +2124,23 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
for(const auto& e : se)
{
if( type_needs_drop_glue(sp, monomorph(e.ent)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
),
(Named,
for(const auto& e : se)
{
if( type_needs_drop_glue(sp, monomorph(e.second.ent)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
)
)
- return false;
),
(Enum,
if(const auto* e = pbe->m_data.opt_Data())
@@ -1788,16 +2148,24 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
for(const auto& var : *e)
{
if( type_needs_drop_glue(sp, monomorph(var.type)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
}
- return false;
),
(Union,
// Unions don't have drop glue unless they impl Drop
- return false;
+ needs_drop_glue = false;
+ ),
+ (ExternType,
+ // Extern types don't have drop glue
+ needs_drop_glue = false;
)
)
+ m_drop_cache.insert(::std::make_pair(ty.clone(), needs_drop_glue));
+ return needs_drop_glue;
),
(Diverge,
return false;
@@ -1892,8 +2260,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
{
TRACE_FUNCTION_F(p << ", signature_only=" << signature_only);
out_params = MonomorphState {};
- TU_MATCHA( (p.m_data), (pe),
- (Generic,
+ TU_MATCH_HDR( (p.m_data), {)
+ TU_ARM(p.m_data, Generic, pe) {
if( pe.m_path.m_components.size() > 1 )
{
const auto& ti = m_crate.get_typeitem_by_path(sp, pe.m_path, /*ignore_crate_name=*/false, /*ignore_last_node=*/true);
@@ -1937,8 +2305,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
)
)
throw "";
- ),
- (UfcsKnown,
+ }
+ TU_ARM(p.m_data, UfcsKnown, pe) {
out_params.self_ty = &*pe.type;
out_params.pp_impl = &pe.trait.m_params;
out_params.pp_method = &pe.params;
@@ -1960,8 +2328,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return false;
const auto& ti = *impl.m_data.as_TraitImpl().impl;
auto it = ti.m_constants.find(pe.item);
- if(it == ti.m_constants.end())
+ if(it == ti.m_constants.end()) {
+ // An impl was found, but it did't have the value
return false;
+ }
if( impl.more_specific_than(best_impl) )
{
@@ -1994,8 +2364,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return &c.data;
}
throw "";
- ),
- (UfcsInherent,
+ }
+ TU_ARM(p.m_data, UfcsInherent, pe) {
out_params.self_ty = &*pe.type;
//out_params.pp_impl = &out_params.pp_impl_data;
out_params.pp_impl = &pe.impl_params;
@@ -2004,12 +2374,12 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
m_crate.find_type_impls(*pe.type, [](const auto&x)->const ::HIR::TypeRef& { return x; }, [&](const auto& impl) {
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
// TODO: Populate pp_impl
- ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "");
// TODO: Specialisation
{
auto fit = impl.m_methods.find(pe.item);
if( fit != impl.m_methods.end() )
{
+ ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args());
DEBUG("- Contains method, good");
rv = ValuePtr { &fit->second.data };
return true;
@@ -2019,6 +2389,7 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
auto it = impl.m_constants.find(pe.item);
if( it != impl.m_constants.end() )
{
+ ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args());
rv = ValuePtr { &it->second.data };
return true;
}
@@ -2026,10 +2397,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return false;
});
return rv;
- ),
- (UfcsUnknown,
+ }
+ TU_ARM(p.m_data, UfcsUnknown, pe) {
BUG(sp, "UfcsUnknown - " << p);
- )
- )
+ }
+ }
throw "";
}
diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp
index 8c9cb9a6..652bad50 100644
--- a/src/hir_typeck/static.hpp
+++ b/src/hir_typeck/static.hpp
@@ -11,18 +11,27 @@
#include "common.hpp"
#include "impl_ref.hpp"
+enum class MetadataType {
+ Unknown, // Unknown still
+ None, // Sized pointer
+ Zero, // No metadata, but still unsized
+ Slice, // usize metadata
+ TraitObject, // VTable pointer metadata
+};
+
class StaticTraitResolve
{
public:
const ::HIR::Crate& m_crate;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::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 +43,8 @@ public:
private:
mutable ::std::map< ::HIR::TypeRef, bool > m_copy_cache;
+ mutable ::std::map< ::HIR::TypeRef, bool > m_clone_cache;
+ mutable ::std::map< ::HIR::TypeRef, bool > m_drop_cache;
public:
StaticTraitResolve(const ::HIR::Crate& crate):
@@ -42,6 +53,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");
@@ -71,30 +84,35 @@ public:
/// \brief State manipulation
/// \{
- template<typename T>
- class NullOnDrop {
- T*& ptr;
- public:
- NullOnDrop(T*& ptr):
- ptr(ptr)
- {}
- ~NullOnDrop() {
- ptr = nullptr;
- }
- };
- NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_impl_generics(const ::HIR::GenericParams& gps) {
+ set_impl_generics_raw(gps);
+ return NullOnDrop<const ::HIR::GenericParams>(m_impl_generics);
+ }
+ NullOnDrop<const ::HIR::GenericParams> set_item_generics(const ::HIR::GenericParams& gps) {
+ set_item_generics_raw(gps);
+ return NullOnDrop<const ::HIR::GenericParams>(m_item_generics);
+ }
+ void set_impl_generics_raw(const ::HIR::GenericParams& gps) {
assert( !m_impl_generics );
m_impl_generics = &gps;
m_type_equalities.clear();
prep_indexes();
- return NullOnDrop< ::HIR::GenericParams>(m_impl_generics);
}
- NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
+ void clear_impl_generics() {
+ m_impl_generics = nullptr;
+ m_type_equalities.clear();
+ prep_indexes();
+ }
+ void set_item_generics_raw(const ::HIR::GenericParams& gps) {
assert( !m_item_generics );
m_item_generics = &gps;
m_type_equalities.clear();
prep_indexes();
- return NullOnDrop< ::HIR::GenericParams>(m_item_generics);
+ }
+ void clear_item_generics() {
+ m_item_generics = nullptr;
+ m_type_equalities.clear();
+ prep_indexes();
}
/// \}
@@ -167,10 +185,10 @@ public:
const ::HIR::SimplePath& des, const ::HIR::PathParams& params,
const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
const ::HIR::TypeRef& self_type,
- ::std::function<void(const ::HIR::PathParams&, ::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ::std::function<void(const ::HIR::PathParams&, ::std::map< RcString, ::HIR::TypeRef>)> callback
) const;
///
- bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const;
+ bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const;
bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const;
@@ -178,9 +196,13 @@ 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 type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const;
bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const;
+ MetadataType metadata_type(const Span& sp, const ::HIR::TypeRef& ty, bool err_on_unknown=false) const;
+
/// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop
bool type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const;
diff --git a/src/ident.cpp b/src/ident.cpp
index da029e21..63fe57ed 100644
--- a/src/ident.cpp
+++ b/src/ident.cpp
@@ -34,7 +34,10 @@ bool Ident::Hygiene::is_visible(const Hygiene& src) const
}
::std::ostream& operator<<(::std::ostream& os, const Ident::Hygiene& x) {
- os << "{" << x.contexts << "}";
+ os << "{" << x.contexts;
+ if( x.search_module )
+ os << " " << x.search_module->ents;
+ os << "}";
return os;
}
diff --git a/src/include/debug.hpp b/src/include/debug.hpp
index 3f059301..534523c2 100644
--- a/src/include/debug.hpp
+++ b/src/include/debug.hpp
@@ -14,13 +14,18 @@
extern int g_debug_indent_level;
+#ifndef DEBUG_EXTRA_ENABLE
+# define DEBUG_EXTRA_ENABLE // Files can override this with their own flag if needed (e.g. `&& g_my_debug_on`)
+#endif
+
#ifndef DISABLE_DEBUG
+# define DEBUG_ENABLED (debug_enabled() DEBUG_EXTRA_ENABLE)
# define INDENT() do { g_debug_indent_level += 1; assert(g_debug_indent_level<300); } while(0)
# define UNINDENT() do { g_debug_indent_level -= 1; } while(0)
-# define DEBUG(ss) do{ if(debug_enabled()) { debug_output(g_debug_indent_level, __FUNCTION__) << ss << ::std::endl; } } while(0)
-# define TRACE_FUNCTION TraceLog _tf_(__func__)
-# define TRACE_FUNCTION_F(ss) TraceLog _tf_(__func__, [&](::std::ostream&__os){ __os << ss; })
-# define TRACE_FUNCTION_FR(ss,ss2) TraceLog _tf_(__func__, [&](::std::ostream&__os){ __os << ss; }, [&](::std::ostream&__os){ __os << ss2;})
+# define DEBUG(ss) do{ if(DEBUG_ENABLED) { debug_output(g_debug_indent_level, __FUNCTION__) << ss << ::std::endl; } } while(0)
+# define TRACE_FUNCTION TraceLog _tf_( DEBUG_ENABLED ? __func__ : nullptr)
+# define TRACE_FUNCTION_F(ss) TraceLog _tf_(DEBUG_ENABLED ? __func__ : nullptr, [&](::std::ostream&__os){ __os << ss; })
+# define TRACE_FUNCTION_FR(ss,ss2) TraceLog _tf_(DEBUG_ENABLED ? __func__ : nullptr, [&](::std::ostream&__os){ __os << ss; }, [&](::std::ostream&__os){ __os << ss2;})
#else
# define INDENT() do { } while(0)
# define UNINDENT() do {} while(0)
diff --git a/src/include/ident.hpp b/src/include/ident.hpp
index b9a6dec5..e8cc4e12 100644
--- a/src/include/ident.hpp
+++ b/src/include/ident.hpp
@@ -8,14 +8,21 @@
#pragma once
#include <vector>
#include <string>
+#include <memory>
+#include <rc_string.hpp>
struct Ident
{
+ struct ModPath
+ {
+ ::std::vector<RcString> ents;
+ };
class Hygiene
{
static unsigned g_next_scope;
::std::vector<unsigned int> contexts;
+ ::std::shared_ptr<ModPath> search_module;
Hygiene(unsigned int index):
contexts({index})
@@ -32,6 +39,7 @@ struct Ident
static Hygiene new_scope_chained(const Hygiene& parent)
{
Hygiene rv;
+ rv.search_module = parent.search_module;
rv.contexts.reserve( parent.contexts.size() + 1 );
rv.contexts.insert( rv.contexts.begin(), parent.contexts.begin(), parent.contexts.end() );
rv.contexts.push_back( ++g_next_scope );
@@ -45,12 +53,22 @@ struct Ident
return rv;
}
+ bool has_mod_path() const {
+ return this->search_module != 0;
+ }
+ const ModPath& mod_path() const {
+ return *this->search_module;
+ }
+ void set_mod_path(ModPath p) {
+ this->search_module.reset( new ModPath(::std::move(p)) );
+ }
+
Hygiene(Hygiene&& x) = default;
Hygiene(const Hygiene& x) = default;
Hygiene& operator=(Hygiene&& x) = default;
Hygiene& operator=(const Hygiene& x) = default;
- // Returns true if an ident with hygine `souce` can see an ident with this hygine
+ // Returns true if an ident with hygine `source` can see an ident with this hygine
bool is_visible(const Hygiene& source) const;
//bool operator==(const Hygiene& x) const { return scope_index == x.scope_index; }
//bool operator!=(const Hygiene& x) const { return scope_index != x.scope_index; }
@@ -59,17 +77,17 @@ struct Ident
};
Hygiene hygiene;
- ::std::string name;
+ RcString name;
Ident(const char* name):
hygiene(),
name(name)
{ }
- Ident(::std::string name):
+ Ident(RcString name):
hygiene(),
name(::std::move(name))
{ }
- Ident(Hygiene hygiene, ::std::string name):
+ Ident(Hygiene hygiene, RcString name):
hygiene(::std::move(hygiene)), name(::std::move(name))
{ }
@@ -78,7 +96,7 @@ struct Ident
Ident& operator=(Ident&& x) = default;
Ident& operator=(const Ident& x) = default;
- ::std::string into_string() {
+ RcString into_string() {
return ::std::move(name);
}
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/rc_string.hpp b/src/include/rc_string.hpp
index 914228c6..0d6ab155 100644
--- a/src/include/rc_string.hpp
+++ b/src/include/rc_string.hpp
@@ -9,67 +9,135 @@
#include <cstring>
#include <ostream>
+#include "../common.hpp"
class RcString
{
unsigned int* m_ptr;
- unsigned int m_len;
public:
RcString():
- m_ptr(nullptr),
- m_len(0)
+ m_ptr(nullptr)
{}
RcString(const char* s, unsigned int len);
RcString(const char* s):
RcString(s, ::std::strlen(s))
{
}
- RcString(const ::std::string& s):
+ explicit RcString(const ::std::string& s):
RcString(s.data(), s.size())
{
}
- RcString(const RcString& x);
+ static RcString new_interned(const ::std::string& s);
+ static RcString new_interned(const char* s);
+
+ RcString(const RcString& x):
+ m_ptr(x.m_ptr)
+ {
+ if( m_ptr ) *m_ptr += 1;
+ }
RcString(RcString&& x):
- m_ptr(x.m_ptr),
- m_len(x.m_len)
+ m_ptr(x.m_ptr)
{
x.m_ptr = nullptr;
- x.m_len = 0;
}
~RcString();
RcString& operator=(const RcString& x)
{
- if( !(&x != this) ) throw "";
-
- this->~RcString();
- new (this) RcString(x);
-
+ if( &x != this )
+ {
+ this->~RcString();
+ m_ptr = x.m_ptr;
+ if( m_ptr ) *m_ptr += 1;
+ }
return *this;
}
RcString& operator=(RcString&& x)
{
- if( !(&x != this) ) throw "";
-
- this->~RcString();
- new (this) RcString( ::std::move(x) );
+ if( &x != this )
+ {
+ this->~RcString();
+ m_ptr = x.m_ptr;
+ x.m_ptr = nullptr;
+ }
return *this;
}
+ const char* begin() const { return c_str(); }
+ const char* end() const { return c_str() + size(); }
+ size_t size() const { return m_ptr ? m_ptr[1] : 0; }
const char* c_str() const {
- if( m_len > 0 ) {
- return reinterpret_cast<const char*>(m_ptr + 1);
+ if( m_ptr )
+ {
+ return reinterpret_cast<const char*>(m_ptr + 2);
}
- else {
+ else
+ {
return "";
}
}
- bool operator==(const RcString& s) const { return *this == s.c_str(); }
- bool operator==(const char* s) const;
- friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x) {
- return os << x.c_str();
+
+ char back() const {
+ assert(size() > 0 );
+ return *(c_str() + size() - 1);
+ }
+
+ Ordering ord(const char* s, size_t l) const;
+ Ordering ord(const RcString& s) const {
+ if( m_ptr == s.m_ptr )
+ return OrdEqual;
+ return ord(s.c_str(), s.size());
+ }
+ bool operator==(const RcString& s) const {
+ if(s.size() != this->size())
+ return false;
+ return this->ord(s) == OrdEqual;
+ }
+ bool operator!=(const RcString& s) const {
+ if(s.size() != this->size())
+ return true;
+ return this->ord(s) != OrdEqual;
+ }
+ bool operator<(const RcString& s) const { return this->ord(s) == OrdLess; }
+ bool operator>(const RcString& s) const { return this->ord(s) == OrdGreater; }
+
+ Ordering ord(const std::string& s) const { return ord(s.data(), s.size()); }
+ bool operator==(const std::string& s) const { return this->ord(s) == OrdEqual; }
+ bool operator!=(const std::string& s) const { return this->ord(s) != OrdEqual; }
+ bool operator<(const std::string& s) const { return this->ord(s) == OrdLess; }
+ bool operator>(const std::string& s) const { return this->ord(s) == OrdGreater; }
+
+ Ordering ord(const char* s) const;
+ bool operator==(const char* s) const { return this->ord(s) == OrdEqual; }
+ bool operator!=(const char* s) const { return this->ord(s) != OrdEqual; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x);
+
+ friend bool operator==(const char* a, const RcString& b) {
+ return b == a;
+ }
+ friend bool operator!=(const char* a, const RcString& b) {
+ return b != a;
+ }
+
+ int compare(size_t o, size_t l, const char* s) const {
+ assert(o <= this->size());
+ return memcmp(this->c_str() + o, s, l);
}
};
+
+namespace std {
+ static inline bool operator==(const string& a, const ::RcString& b) {
+ return b == a;
+ }
+ static inline bool operator!=(const string& a, const ::RcString& b) {
+ return b != a;
+ }
+ template<> struct hash<RcString>
+ {
+ size_t operator()(const RcString& s) const noexcept;
+ };
+}
diff --git a/src/include/span.hpp b/src/include/span.hpp
index d41fa81e..970a2ad0 100644
--- a/src/include/span.hpp
+++ b/src/include/span.hpp
@@ -31,6 +31,7 @@ struct ProtoSpan
};
struct Span
{
+//public:
::std::shared_ptr<Span> outer_span; // Expansion target for macros
RcString filename;
diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp
index 1e16ce09..88a6258c 100644
--- a/src/include/synext_decorator.hpp
+++ b/src/include/synext_decorator.hpp
@@ -12,6 +12,7 @@
#include <string>
#include <memory>
#include <span.hpp>
+#include <slice.hpp>
#include "../ast/item.hpp"
#include "../ast/expr.hpp"
@@ -49,7 +50,7 @@ public:
virtual AttrStage stage() const = 0;
virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
- virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const { unexpected(sp, mi, "item"); }
// NOTE: To delete, set the type to `_`
virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
// NOTE: To delete, clear the name
diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp
index 60b52d89..e62a6126 100644
--- a/src/include/synext_macro.hpp
+++ b/src/include/synext_macro.hpp
@@ -27,8 +27,10 @@ class TokenStream;
class ExpandProcMacro
{
public:
- virtual ~ExpandProcMacro() = default;
- virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0;
+ virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) = 0;
+ virtual ::std::unique_ptr<TokenStream> expand_ident(const Span& sp, const AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) {
+ ERROR(sp, E0000, "macro doesn't take an identifier");
+ }
};
struct MacroDef;
diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp
index bcc9eb3d..5a3359b8 100644
--- a/src/include/tagged_union.hpp
+++ b/src/include/tagged_union.hpp
@@ -28,7 +28,6 @@
#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__)
#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__)
-
// Argument iteration
#define TU_DISP0(n)
#define TU_DISP1(n, _1) n _1
@@ -105,7 +104,7 @@
*/ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/*
*/ default: {TU_EXP DEF;} break;/*
*/}
-#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME;
+#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME;
#define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2)
#define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars
#define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/*
@@ -116,8 +115,15 @@
#define TU_IFLET(CLASS, VAR, TAG, NAME, ...) if(VAR.tag() == CLASS::TAG_##TAG) { auto& NAME = VAR.as_##TAG(); (void)&NAME; __VA_ARGS__ }
+#define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
+#define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
+// Evil hack: two for loops, the inner stops the outer after it's done.
+#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+
+#define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
+#define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
// Evil hack: two for loops, the inner stops the outer after it's done.
-#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference<decltype(tu_match_hdr2_v)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
//#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST)
#define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST)
diff --git a/src/include/target_version.hpp b/src/include/target_version.hpp
new file mode 100644
index 00000000..07528276
--- /dev/null
+++ b/src/include/target_version.hpp
@@ -0,0 +1,19 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * include/target_version.hpp
+ * - mrustc target lanuage version definitions
+ */
+#pragma once
+
+enum class TargetVersion {
+ Rustc1_19,
+ Rustc1_29,
+};
+
+// Defined in main.cpp
+extern TargetVersion gTargetVersion;
+
+#define TARGETVER_1_19 (gTargetVersion == TargetVersion::Rustc1_19)
+#define TARGETVER_1_29 (gTargetVersion == TargetVersion::Rustc1_29)
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index a393ba46..927a3585 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -93,60 +93,43 @@ private:
CapturedVal& get_cap(const ::std::vector<unsigned int>& iterations, unsigned int name_idx);
};
-/// Simple pattern entry for macro_rules! arm patterns
-TAGGED_UNION( SimplePatEnt, End,
- // End of the pattern stream
- (End, struct{}),
- // Expect a specific token
- (ExpectTok, Token),
- // Expect a pattern match
- (ExpectPat, struct {
- MacroPatEnt::Type type;
- unsigned int idx;
- }),
- // Compare the head of the input stream and poke the pattern stream
- (IfTok, struct {
- bool is_equal;
- Token tok;
- }),
- // Compare the head of the input stream and poke the pattern stream
- (IfPat, struct {
- bool is_equal;
- MacroPatEnt::Type type;
- })
- );
class MacroPatternStream
{
- const ::std::vector<MacroPatEnt>* m_pattern;
- // Position in each nested pattern
- ::std::vector<unsigned int> m_pos;
+ const ::std::vector<SimplePatEnt>& m_simple_ents;
+ size_t m_cur_pos;
+
+ bool m_last_was_cond;
+ bool m_condition_met;
+ ::std::vector<bool> m_condition_history;
+
+ const ::std::vector<bool>* m_condition_replay;
+ size_t m_condition_replay_pos;
+
// Iteration index of each active loop level
::std::vector<unsigned int> m_loop_iterations;
- ::std::vector<SimplePatEnt> m_stack;
- unsigned int m_skip_count;
-
- SimplePatEnt m_peek_cache;
bool m_peek_cache_valid = false;
+ const SimplePatEnt* m_peek_cache;
- bool m_break_if_not = false;
- bool m_condition_fired = false;
public:
- MacroPatternStream(const ::std::vector<MacroPatEnt>& pattern):
- m_pattern(&pattern),
- m_pos({0})
+ MacroPatternStream(const ::std::vector<SimplePatEnt>& ents, const ::std::vector<bool>* condition_replay=nullptr):
+ m_simple_ents(ents),
+ m_cur_pos(0),
+ m_last_was_cond(false),
+ m_condition_replay(condition_replay),
+ m_condition_replay_pos(0)
{
}
/// Get the next pattern entry
- SimplePatEnt next();
+ const SimplePatEnt& next();
const SimplePatEnt& peek() {
if( !m_peek_cache_valid ) {
- m_peek_cache = next();
+ m_peek_cache = &next();
m_peek_cache_valid = true;
}
- return m_peek_cache;
+ return *m_peek_cache;
}
/// Inform the stream that the `if` rule that was just returned succeeded
@@ -156,16 +139,9 @@ public:
return m_loop_iterations;
}
-private:
- SimplePatEnt emit_loop_start(const MacroPatEnt& pat);
-
- SimplePatEnt emit_seq(SimplePatEnt v1, SimplePatEnt v2) {
- assert( m_stack.empty() );
- m_stack.push_back( mv$(v2) );
- return v1;
+ ::std::vector<bool> take_history() {
+ return ::std::move(m_condition_history);
}
-
- void break_loop();
};
// === Prototypes ===
@@ -312,223 +288,76 @@ bool ParameterMappings::dec_count(const ::std::vector<unsigned int>& iterations,
// MacroPatternStream
// ------------------------------------
-SimplePatEnt MacroPatternStream::next()
+const SimplePatEnt& MacroPatternStream::next()
{
- TRACE_FUNCTION_F("m_pos=[" << m_pos << "], m_stack.size()=" << m_stack.size());
- assert(m_pos.size() >= 1);
-
if( m_peek_cache_valid ) {
m_peek_cache_valid = false;
- return mv$(m_peek_cache);
+ return *m_peek_cache;
}
- // Pop off the generation stack
- if( ! m_stack.empty() ) {
- auto rv = mv$(m_stack.back());
- m_stack.pop_back();
- return rv;
- }
-
- if( m_break_if_not && ! m_condition_fired ) {
- // Break out of the current loop then continue downwards.
- break_loop();
- }
-
- m_skip_count = 0;
- m_break_if_not = false;
- m_condition_fired = false;
-
- const MacroPatEnt* parent_pat = nullptr;
- decltype(m_pattern) parent_ents = nullptr;
- const auto* ents = m_pattern;
- for(unsigned int i = 0; i < m_pos.size() - 1; i ++)
- {
- auto idx = m_pos[i];
- //DEBUG(i << " idx=" << idx << " ents->size()=" << ents->size());
- assert( idx < ents->size() );
- assert( (*ents)[idx].type == MacroPatEnt::PAT_LOOP );
- parent_pat = &(*ents)[idx];
- parent_ents = ents;
- ents = &parent_pat->subpats;
- }
-
- DEBUG( (m_pos.size()-1) << " " << m_pos.back() << " / " << ents->size());
- if( m_pos.back() < ents->size() )
- {
- const auto& pat = ents->at( m_pos.back() );
-
- if( pat.type == MacroPatEnt::PAT_LOOP ) {
- DEBUG("Enter " << pat);
- // Increase level, return entry control
- m_pos.push_back( 0 );
- m_loop_iterations.push_back( 0 );
-
- if( pat.name == "*" )
- {
- return emit_loop_start(pat);
- }
- else
- {
- // If the name is "+" then this is should always be entered, so just recurse
- assert( pat.name == "+" );
- return next();
- }
- }
- else if( pat.type == MacroPatEnt::PAT_TOKEN ) {
- m_pos.back() += 1;
- return SimplePatEnt::make_ExpectTok( pat.tok.clone() );
- }
- else {
- m_pos.back() += 1;
- return SimplePatEnt::make_ExpectPat({ pat.type, pat.name_index });
- }
- }
- else
+ for(;;)
{
- if( parent_pat )
+ // If not replaying, and the previous entry was a conditional, record the result of that conditional
+ if( !m_condition_replay && m_last_was_cond )
{
- // Last entry in a loop - return the breakout control
- // - Reset the loop back to the start
- m_pos.back() = 0;
- m_loop_iterations.back() += 1;
-
- // - Emit break conditions
- if( parent_pat->tok == TOK_NULL ) {
- // Loop separator is TOK_NULL - get the first token of the loop and use it.
- // - This shares the code that controls if a loop is entered
- DEBUG("No separator");
- return emit_loop_start(*parent_pat);
- }
- else {
- // If the next token is the same as the separator emit: Expect(separator), ShouldEnter
-
- auto i = m_pos[ m_pos.size() - 2 ] + 1;
- if( i < parent_ents->size() )
- {
- DEBUG("sep = " << parent_pat->tok << ", next = " << parent_ents->at(i) << ", start = " << ents->at(0));
- if( parent_ents->at(i).type == MacroPatEnt::PAT_TOKEN && parent_pat->tok == parent_ents->at(i).tok )
- {
- DEBUG("MAGIC: Reverse conditions for case where sep==next");
- // > Mark to skip the next token after the end of the loop
- m_skip_count = 1;
- // - Yeild `EXPECT sep` then the entry condition of this loop
- auto pat = emit_loop_start(*parent_pat);
- m_stack.push_back( mv$(pat) );
- return SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() );
- }
- }
- // - Yeild `IF NOT sep BREAK` and `EXPECT sep`
- DEBUG("Separator = " << parent_pat->tok);
- return emit_seq(
- SimplePatEnt::make_IfTok({ false, parent_pat->tok.clone() }),
- SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() )
- );
- }
+ m_condition_history.push_back(m_condition_met);
}
- else
- {
- // End of the input sequence
- return SimplePatEnt::make_End({});
+ m_last_was_cond = false;
+ // End of list? return End entry
+ if( m_cur_pos == m_simple_ents.size() ) {
+ static SimplePatEnt END = SimplePatEnt::make_End({});
+ return END;
}
- }
-}
-
-namespace {
- void get_loop_entry_pats(const MacroPatEnt& pat, ::std::vector<const MacroPatEnt*>& entry_pats)
- {
- assert( pat.type == MacroPatEnt::PAT_LOOP );
-
- // If this pattern is a loop, get the entry concrete patterns for it
- // - Otherwise, just
- unsigned int i = 0;
- while( i < pat.subpats.size() && pat.subpats[i].type == MacroPatEnt::PAT_LOOP )
+ const auto& cur_ent = m_simple_ents[m_cur_pos];
+ // If replaying, and this is a conditional
+ if( m_condition_replay && cur_ent.is_If() )
{
- const auto& cur_pat = pat.subpats[i];
- bool is_optional = (cur_pat.name == "*");
-
- get_loop_entry_pats(cur_pat, entry_pats);
-
- if( !is_optional )
- {
- // Non-optional loop, MUST be entered, so return after recursing
- return ;
- }
- // Optional, so continue the loop.
- i ++;
- }
-
- // First non-loop pattern
- if( i < pat.subpats.size() )
- {
- entry_pats.push_back( &pat.subpats[i] );
- }
- }
-} // namespace
-
-/// Returns (and primes m_stack) the rules to control the start of a loop
-/// This code emits rules to break out of the loop if the entry conditions are not met
-SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat)
-{
- // Find the next non-loop pattern to control if this loop should be entered
- ::std::vector<const MacroPatEnt*> m_entry_pats;
-
- get_loop_entry_pats(pat, m_entry_pats);
- DEBUG("m_entry_pats = [" << FMT_CB(ss, for(const auto* p : m_entry_pats) { ss << *p << ","; }) << "]");
-
- struct H {
- static SimplePatEnt get_if(bool flag, const MacroPatEnt& mpe) {
- if( mpe.type == MacroPatEnt::PAT_TOKEN )
- return SimplePatEnt::make_IfTok({ flag, mpe.tok.clone() });
+ // Skip the conditional (following its target or just skipping over)
+ if( (*m_condition_replay)[m_condition_replay_pos++] )
+ m_cur_pos = cur_ent.as_If().jump_target;
else
- return SimplePatEnt::make_IfPat({ flag, mpe.type });
+ m_cur_pos += 1;
+ continue ;
}
- };
-
- const auto* entry_pat = m_entry_pats.back();
- m_entry_pats.pop_back();
- if( m_entry_pats.size() > 0 )
- {
- DEBUG("Multiple entry possibilities, reversing condition");
- m_break_if_not = true;
- for(auto pat_ptr : m_entry_pats)
- {
- m_stack.push_back( H::get_if(true, *pat_ptr) );
+ m_cur_pos += 1;
+ TU_MATCH_HDRA( (cur_ent), {)
+ default:
+ if( cur_ent.is_If() )
+ {
+ m_last_was_cond = true;
+ m_condition_met = false;
+ }
+ return cur_ent;
+ TU_ARMA(End, _e)
+ BUG(Span(), "Unexpected End");
+ TU_ARMA(Jump, e)
+ m_cur_pos = e.jump_target;
+ TU_ARMA(LoopStart, _e) {
+ m_loop_iterations.push_back(0);
+ }
+ TU_ARMA(LoopNext, _e) {
+ m_loop_iterations.back() += 1;
+ }
+ TU_ARMA(LoopEnd, _e) {
+ m_loop_iterations.pop_back();
+ }
}
- return H::get_if(true, *entry_pat);
- }
- else
- {
- // Emit an if based on it
- return H::get_if(false, *entry_pat);
}
}
void MacroPatternStream::if_succeeded()
{
- if( m_break_if_not )
- {
- m_condition_fired = true;
- }
- else
- {
- break_loop();
+ assert(m_cur_pos > 0);
+ assert(m_last_was_cond);
+ TU_MATCH_HDRA( (m_simple_ents[m_cur_pos-1]), {)
+ default:
+ BUG(Span(), "Unexpected " << m_simple_ents[m_cur_pos-1]);
+ TU_ARMA(If, e) {
+ ASSERT_BUG(Span(), e.jump_target < m_simple_ents.size(), "Jump target " << e.jump_target << " out of range " << m_simple_ents.size());
+ m_cur_pos = e.jump_target;
+ }
}
-}
-void MacroPatternStream::break_loop()
-{
- DEBUG("- Break out of loop, m_skip_count = " << m_skip_count);
- // Break out of an active loop (pop level and increment parent level)
- assert( m_pos.size() >= 1 );
- // - This should never be called when on the top level
- assert( m_pos.size() != 1 );
-
- // HACK: Clear the stack if an if succeeded
- m_stack.clear();
-
- m_pos.pop_back();
- m_pos.back() += 1 + m_skip_count;
-
- m_loop_iterations.pop_back();
+ m_condition_met = true;
}
// ----------------------------------------------------------------
@@ -576,7 +405,7 @@ class MacroExpander:
{
const RcString m_macro_filename;
- const ::std::string m_crate_name;
+ const RcString m_crate_name;
::std::shared_ptr<Span> m_invocation_span;
ParameterMappings m_mappings;
@@ -589,7 +418,7 @@ class MacroExpander:
public:
MacroExpander(const MacroExpander& x) = delete;
- MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
+ MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, RcString crate_name):
m_macro_filename( FMT("Macro:" << macro_name) ),
m_crate_name( mv$(crate_name) ),
m_invocation_span( new Span(sp) ),
@@ -616,69 +445,6 @@ namespace {
}
}
-// TODO: This shouldn't exist, and can false-positives
-// - Ideally, this would use consume_from_frag (which takes a clone-able input)
-bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type)
-{
- switch(type)
- {
- case MacroPatEnt::PAT_TOKEN:
- BUG(lex.point_span(), "");
- case MacroPatEnt::PAT_LOOP:
- BUG(lex.point_span(), "");
- case MacroPatEnt::PAT_BLOCK:
- return LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK;
- case MacroPatEnt::PAT_IDENT:
- return LOOK_AHEAD(lex) == TOK_IDENT || is_reserved_word(LOOK_AHEAD(lex));
- case MacroPatEnt::PAT_TT:
- switch(LOOK_AHEAD(lex))
- {
- case TOK_EOF:
- case TOK_PAREN_CLOSE:
- case TOK_BRACE_CLOSE:
- case TOK_SQUARE_CLOSE:
- return false;
- default:
- return true;
- }
- case MacroPatEnt::PAT_PATH:
- return is_token_path( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_TYPE:
- return is_token_type( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_EXPR:
- return is_token_expr( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_STMT:
- return is_token_stmt( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_PAT:
- return is_token_pat( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_META:
- return LOOK_AHEAD(lex) == TOK_IDENT || LOOK_AHEAD(lex) == TOK_INTERPOLATED_META;
- case MacroPatEnt::PAT_ITEM:
- return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT;
- }
- BUG(lex.point_span(), "Fell through");
-}
-bool Macro_TryPattern(TokenStream& lex, const MacroPatEnt& pat)
-{
- DEBUG("pat = " << pat);
- Token tok;
- switch(pat.type)
- {
- case MacroPatEnt::PAT_TOKEN: {
- GET_TOK(tok, lex);
- bool rv = (tok == pat.tok);
- PUTBACK(tok, lex);
- return rv;
- }
- case MacroPatEnt::PAT_LOOP:
- if( pat.name == "*" )
- return true;
- return Macro_TryPattern(lex, pat.subpats[0]);
- default:
- return Macro_TryPatternCap(lex, pat.type);
- }
-}
-
InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type type)
{
Token tok;
@@ -723,6 +489,11 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
CHECK_TOK(tok, TOK_IDENT);
// TODO: TOK_INTERPOLATED_IDENT
return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) );
+ case MacroPatEnt::PAT_VIS:
+ return InterpolatedFragment( Parse_Publicity(lex, /*allow_restricted=*/true) );
+ case MacroPatEnt::PAT_LIFETIME:
+ GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
+ return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) );
}
throw "";
}
@@ -731,6 +502,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod)
{
TRACE_FUNCTION_F("'" << name << "', " << input);
+ DEBUG("rules.m_hygiene = " << rules.m_hygiene);
ParameterMappings bound_tts;
unsigned int rule_index = Macro_InvokeRules_MatchPattern(sp, rules, mv$(input), mod, bound_tts);
@@ -752,7 +524,6 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
return ::std::unique_ptr<TokenStream>( ret_ptr );
}
-#if 1
// Collection of functions that consume a specific fragment type from a token stream
// - Does very loose consuming
namespace
@@ -1069,9 +840,11 @@ namespace
case TOK_PAREN_OPEN:
case TOK_SQUARE_OPEN:
return consume_tt(lex);
+ case TOK_IDENT:
+ if( TARGETVER_1_29 && lex.next_tok().istr() == "dyn" )
+ lex.consume();
case TOK_RWORD_SUPER:
case TOK_RWORD_SELF:
- case TOK_IDENT:
case TOK_DOUBLE_COLON:
case TOK_INTERPOLATED_IDENT:
case TOK_INTERPOLATED_PATH:
@@ -1189,7 +962,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())
{
@@ -1335,6 +1109,11 @@ namespace
lex.consume();
break;
+ // Possibly a left-open (or full-open) range literal
+ case TOK_DOUBLE_DOT:
+ case TOK_DOUBLE_DOT_EQUAL:
+ case TOK_TRIPLE_DOT:
+ break;
case TOK_RWORD_UNSAFE:
lex.consume();
@@ -1490,10 +1269,28 @@ namespace
case TOK_EXCLAM_EQUAL:
case TOK_DOUBLE_AMP:
case TOK_DOUBLE_PIPE:
- case TOK_DOUBLE_DOT:
+ case TOK_DOUBLE_DOT_EQUAL:
case TOK_TRIPLE_DOT:
lex.consume();
break;
+ case TOK_DOUBLE_DOT:
+ lex.consume();
+ DEBUG("TOK_DOUBLE_DOT => " << lex.next());
+ switch(lex.next())
+ {
+ case TOK_EOF:
+ return true;
+ case TOK_COMMA:
+ case TOK_SEMICOLON:
+ case TOK_BRACE_CLOSE:
+ case TOK_PAREN_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ break;
case TOK_EQUAL:
case TOK_PLUS_EQUAL:
case TOK_DASH_EQUAL:
@@ -1570,7 +1367,7 @@ namespace
return true;
// Macro invocation
// TODO: What about `union!` as a macro? Needs to be handled below
- if( (lex.next() == TOK_IDENT && lex.next_tok().str() != "union")
+ if( (lex.next() == TOK_IDENT && lex.next_tok().istr() != "union")
|| lex.next() == TOK_RWORD_SELF
|| lex.next() == TOK_RWORD_SUPER
|| lex.next() == TOK_DOUBLE_COLON
@@ -1580,6 +1377,7 @@ namespace
return false;
if( !lex.consume_if(TOK_EXCLAM) )
return false;
+ lex.consume_if(TOK_IDENT);
bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
consume_tt(lex);
if( need_semicolon )
@@ -1705,29 +1503,46 @@ namespace
return false;
return consume_tt(lex);
case TOK_IDENT:
- if( lex.next_tok().str() != "union" )
- return false;
- lex.consume();
- if( lex.next() == TOK_EXCLAM )
+ if( lex.next_tok().istr() == "union" )
{
- bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
- consume_tt(lex);
- if( need_semicolon )
+ lex.consume();
+ if( lex.next() == TOK_EXCLAM )
+ {
+ bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
+ consume_tt(lex);
+ if( need_semicolon )
+ {
+ if( !lex.consume_if(TOK_SEMICOLON) )
+ return false;
+ }
+ return true;
+ }
+ else
{
- if( !lex.consume_if(TOK_SEMICOLON) )
+ if( !H::maybe_generics(lex) )
return false;
+ if( !H::maybe_where(lex) )
+ return false;
+ if( lex.next() != TOK_BRACE_OPEN )
+ return false;
+ return consume_tt(lex);
}
- return true;
}
- else
+ else if( lex.next_tok().istr() == "auto" )
{
- if( !H::maybe_generics(lex) )
- return false;
- if( !H::maybe_where(lex) )
- return false;
- if( lex.next() != TOK_BRACE_OPEN )
+ lex.consume();
+ if( lex.consume_if(TOK_RWORD_TRAIT) )
+ {
+ goto trait;
+ }
+ else
+ {
return false;
- return consume_tt(lex);
+ }
+ }
+ else
+ {
+ return false;
}
break;
// const fn
@@ -1754,6 +1569,19 @@ namespace
return false;
}
break;
+ case TOK_RWORD_TRAIT:
+ lex.consume();
+ trait:
+ if( !lex.consume_if(TOK_IDENT) )
+ return false;
+
+ if( !H::maybe_generics(lex) )
+ return false;
+ if(lex.next() != TOK_BRACE_OPEN)
+ return false;
+ if( !consume_tt(lex) )
+ return false;
+ break;
case TOK_RWORD_EXTERN:
lex.consume();
if( lex.consume_if(TOK_RWORD_CRATE) )
@@ -1815,6 +1643,26 @@ namespace
}
return true;
}
+ bool consume_vis(TokenStreamRO& lex)
+ {
+ TRACE_FUNCTION;
+ if( lex.consume_if(TOK_INTERPOLATED_VIS) || lex.consume_if(TOK_RWORD_CRATE) )
+ {
+ return true;
+ }
+ else if( lex.consume_if(TOK_RWORD_PUB) )
+ {
+ if( lex.next() == TOK_PAREN_OPEN )
+ {
+ return consume_tt(lex);
+ }
+ return true;
+ }
+ else
+ {
+ return true;
+ }
+ }
bool consume_from_frag(TokenStreamRO& lex, MacroPatEnt::Type type)
{
@@ -1823,7 +1671,7 @@ namespace
{
case MacroPatEnt::PAT_TOKEN:
case MacroPatEnt::PAT_LOOP:
- throw "";
+ BUG(Span(), "Encountered " << type << " in consume_from_frag");;
case MacroPatEnt::PAT_BLOCK:
if( lex.next() == TOK_BRACE_OPEN ) {
return consume_tt(lex);
@@ -1889,6 +1737,10 @@ namespace
break;
case MacroPatEnt::PAT_ITEM:
return consume_item(lex);
+ case MacroPatEnt::PAT_VIS:
+ return consume_vis(lex);
+ case MacroPatEnt::PAT_LIFETIME:
+ return lex.consume_if(TOK_LIFETIME);
}
return true;
}
@@ -1897,14 +1749,9 @@ namespace
unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts)
{
TRACE_FUNCTION;
+ ASSERT_BUG(sp, rules.m_rules.size() > 0, "Empty macro_rules set");
- struct ActiveArm {
- unsigned int index;
- MacroPatternStream pat_stream;
- TokenStreamRO in_stream;
- };
-
- ::std::vector<size_t> matches;
+ ::std::vector< ::std::pair<size_t, ::std::vector<bool>> > matches;
for(size_t i = 0; i < rules.m_rules.size(); i ++)
{
auto lex = TokenStreamRO(input);
@@ -1913,29 +1760,38 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
bool fail = false;
for(;;)
{
- auto pat = arm_stream.next();
+ const auto& pat = arm_stream.next();
+ DEBUG(i << " " << pat);
if(pat.is_End())
{
- DEBUG(i << " End");
if( lex.next() != TOK_EOF )
fail = true;
break;
}
- else if( const auto* e = pat.opt_IfPat() )
+ else if( const auto* e = pat.opt_If() )
{
- DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")");
auto lc = lex.clone();
- if( consume_from_frag(lc, e->type) == e->is_equal )
+ bool rv = true;
+ for(const auto& check : e->ents)
{
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
+ if( check.ty != MacroPatEnt::PAT_TOKEN ) {
+ if( !consume_from_frag(lc, check.ty) )
+ {
+ rv = false;
+ break;
+ }
+ }
+ else
+ {
+ if( lc.next_tok() != check.tok )
+ {
+ rv = false;
+ break;
+ }
+ lc.consume();
+ }
}
- }
- else if( const auto* e = pat.opt_IfTok() )
- {
- DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")");
- const auto& tok = lex.next_tok();
- if( (tok == e->tok) == e->is_equal )
+ if( rv == e->is_equal )
{
DEBUG("- Succeeded");
arm_stream.if_succeeded();
@@ -1970,7 +1826,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
if( ! fail )
{
- matches.push_back(i);
+ matches.push_back( ::std::make_pair(i, arm_stream.take_history()) );
DEBUG(i << " MATCHED");
}
else
@@ -1982,6 +1838,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
if( matches.size() == 0 )
{
// ERROR!
+ // TODO: Keep track of where each arm failed.
TODO(sp, "No arm matched");
}
else
@@ -1989,12 +1846,13 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
// yay!
// NOTE: There can be multiple arms active, take the first.
- auto i = matches[0];
+ auto i = matches[0].first;
+ const auto& history = matches[0].second;
DEBUG("Evalulating arm " << i);
auto lex = TTStreamO(sp, mv$(input));
SET_MODULE(lex, mod);
- auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern);
+ auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern, &history);
struct Capture {
unsigned int binding_idx;
@@ -2006,30 +1864,15 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
for(;;)
{
- auto pat = arm_stream.next();
+ const auto& pat = arm_stream.next();
+ DEBUG(i << " " << pat);
if(pat.is_End())
{
break;
}
- else if( const auto* e = pat.opt_IfPat() )
+ else if( pat.is_If() )
{
- DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")");
- if( Macro_TryPatternCap(lex, e->type) == e->is_equal )
- {
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
- }
- }
- else if( const auto* e = pat.opt_IfTok() )
- {
- DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")");
- auto tok = lex.getToken();
- if( (tok == e->tok) == e->is_equal )
- {
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
- }
- lex.putback( mv$(tok) );
+ BUG(sp, "Unexpected If pattern during final matching - " << pat);
}
else if( const auto* e = pat.opt_ExpectTok() )
{
@@ -2037,7 +1880,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
DEBUG(i << " ExpectTok(" << *e << ") == " << tok);
if( tok != *e )
{
- ERROR(sp, E0000, "Expected token in match arm");
+ ERROR(sp, E0000, "Expected token " << *e << " in match arm, got " << tok);
break;
}
}
@@ -2064,305 +1907,6 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
return i;
}
}
-#else
-unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts)
-{
- TRACE_FUNCTION;
- Span sp;// = input.span();
-
- struct Capture {
- unsigned int binding_idx;
- ::std::vector<unsigned int> iterations;
- unsigned int cap_idx;
- };
- struct ActiveArm {
- unsigned int index;
- ::std::vector<Capture> captures;
- MacroPatternStream stream;
- };
- // - List of active rules (rules that haven't yet failed)
- ::std::vector< ActiveArm > active_arms;
- active_arms.reserve( rules.m_rules.size() );
- for(unsigned int i = 0; i < rules.m_rules.size(); i ++)
- {
- active_arms.push_back( ActiveArm { i, {}, MacroPatternStream(rules.m_rules[i].m_pattern) } );
- }
-
- // - List of captured values
- ::std::vector<InterpolatedFragment> captures;
-
- TTStreamO lex(sp, mv$(input) );
- SET_MODULE(lex, mod);
- while(true)
- {
- DEBUG("--- ---");
- // 1. Get concrete patterns for all active rules (i.e. no If* patterns)
- ::std::vector<SimplePatEnt> arm_pats;
- for(auto& arm : active_arms)
- {
- auto idx = arm.index;
- SimplePatEnt pat;
- // Consume all If* rules
- do
- {
- pat = arm.stream.next();
- TU_IFLET( SimplePatEnt, pat, IfPat, e,
- DEBUG(idx << " IfPat(" << (e.is_equal ? "==" : "!=") << " ?" << e.type << ")");
- if( Macro_TryPatternCap(lex, e.type) == e.is_equal )
- {
- DEBUG("- Succeeded");
- arm.stream.if_succeeded();
- }
- )
- else TU_IFLET( SimplePatEnt, pat, IfTok, e,
- DEBUG(idx << " IfTok(" << (e.is_equal ? "==" : "!=") << " ?" << e.tok << ")");
- auto tok = lex.getToken();
- if( (tok == e.tok) == e.is_equal )
- {
- DEBUG("- Succeeded");
- arm.stream.if_succeeded();
- }
- lex.putback( mv$(tok) );
- )
- else {
- break;
- }
- } while( pat.is_IfPat() || pat.is_IfTok() );
-
- TU_MATCH( SimplePatEnt, (pat), (e),
- (IfPat, BUG(sp, "IfTok unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- DEBUG(idx << " ExpectTok(" << e << ")");
- ),
- (ExpectPat,
- DEBUG(idx << " ExpectPat(" << e.type << " => $" << e.idx << ")");
- ),
- (End,
- DEBUG(idx << " End");
- )
- )
- arm_pats.push_back( mv$(pat) );
- }
- assert( arm_pats.size() == active_arms.size() );
-
- // 2. Prune imposible arms
- for(unsigned int i = 0, j = 0; i < arm_pats.size(); )
- {
- auto idx = active_arms[i].index;
- const auto& pat = arm_pats[i];
- bool fail = false;
-
- TU_MATCH( SimplePatEnt, (pat), (e),
- (IfPat, BUG(sp, "IfTok unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- auto tok = lex.getToken();
- DEBUG(j<<"="<<idx << " ExpectTok(" << e << ") == " << tok);
- fail = !(tok == e);
- lex.putback( mv$(tok) );
- ),
- (ExpectPat,
- DEBUG(j<<"="<<idx << " ExpectPat(" << e.type << " => $" << e.idx << ")");
- fail = !Macro_TryPatternCap(lex, e.type);
- ),
- (End,
- DEBUG(j<<"="<<idx << " End");
- fail = !(lex.lookahead(0) == TOK_EOF);
- )
- )
- if( fail ) {
- DEBUG("- Failed arm " << active_arms[i].index);
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- i ++;
- }
- j ++;
- }
-
- if( arm_pats.size() == 0 ) {
- auto tok = lex.getToken();
- ERROR(tok.get_pos(), E0000, "No rules expected " << tok);
- }
-
- // 3. If there is a token pattern in the list, take that arm (and any other token arms)
- const SimplePatEnt* tok_pat = nullptr;
- unsigned int ident_pat_idx = arm_pats.size();
- bool has_non_ident_pat = false;
- for( unsigned int i = 0; i < arm_pats.size(); i ++ )
- {
- const auto& pat = arm_pats[i];
- TU_IFLET(SimplePatEnt, pat, ExpectTok, e,
- if( tok_pat ) {
- if( e != tok_pat->as_ExpectTok() )
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms - " << tok_pat->as_ExpectTok() << " vs " << e);
- }
- else {
- tok_pat = &pat;
- }
- )
- else TU_IFLET(SimplePatEnt, pat, ExpectPat, e,
- if( e.type == MacroPatEnt::PAT_IDENT ) {
- ident_pat_idx = i;
- }
- else {
- has_non_ident_pat = true;
- }
- )
- }
-
- if( tok_pat )
- {
- auto tok = lex.getToken();
- const auto& e = tok_pat->as_ExpectTok();
- // NOTE: This should never fail.
- if( tok != e ) {
- ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected " << e);
- }
- }
- else
- {
- if( has_non_ident_pat && ident_pat_idx < arm_pats.size() )
- {
- // For all :ident patterns present, check the next rule.
- // - If this rule would fail, remove the arm.
- bool ident_rule_kept = false;
- for( unsigned int i = 0; i < arm_pats.size(); )
- {
- bool discard = false;
- const auto& pat = arm_pats[i];
- const auto& e = pat.as_ExpectPat();
- if( e.type == MacroPatEnt::PAT_IDENT )
- {
- const auto& next = active_arms[i].stream.peek();
- TU_MATCHA( (next), (ne),
- (IfPat, TODO(sp, "Handle IfPat following a conflicting :ident");),
- (IfTok, TODO(sp, "IfTok following a conflicting :ident");),
- (ExpectTok,
- if( ne.type() != lex.lookahead(1) ) {
- DEBUG("Discard active arm " << i << " due to next token mismatch");
- discard = true;
- }
- else {
- ident_rule_kept = true;
- }
- ),
- (ExpectPat,
- TODO(sp, "Handle ExpectPat following a conflicting :ident");
- ),
- (End, TODO(sp, "Handle End following a conflicting :ident"); )
- )
- }
-
- if( discard ) {
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- ++ i;
- }
- }
-
- // If there are any remaining ident rules, erase the non-ident rules.
- if( ident_rule_kept ) {
- // If no rules were discarded, remove the non-ident rules
- for( unsigned int i = 0; i < arm_pats.size(); )
- {
- if( arm_pats[i].as_ExpectPat().type != MacroPatEnt::PAT_IDENT ) {
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- ++ i;
- }
- }
- }
- assert(arm_pats.size() > 0);
- assert(arm_pats.size() == active_arms.size());
- }
-
- // 3. Check that all remaining arms are the same pattern.
- const auto& active_pat = arm_pats[0];
- for(unsigned int i = 1; i < arm_pats.size(); i ++)
- {
- if( active_pat.tag() != arm_pats[i].tag() ) {
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms "
- << "- " << active_arms[0].index << " SimplePatEnt::" << active_pat.tag_str()
- << " vs " << active_arms[i].index<< " SimplePatEnt::" << arm_pats[i].tag_str()
- );
- }
- TU_MATCH( SimplePatEnt, (active_pat, arm_pats[i]), (e1, e2),
- (IfPat, BUG(sp, "IfPat unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- BUG(sp, "ExpectTok unexpected here");
- ),
- (ExpectPat,
- // Can fail, as :expr and :stmt overlap in their trigger set
- if( e1.type != e2.type ) {
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms - mismatched patterns " << e1.type << " and " << e2.type);
- }
- ),
- (End,
- )
- )
- }
-
- // 4. Apply patterns.
- TU_MATCH( SimplePatEnt, (arm_pats[0]), (e),
- (End,
- auto tok = lex.getToken();
- if( tok.type() != TOK_EOF ) {
- ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected TOK_EOF");
- }
- // NOTE: There can be multiple arms active, take the first.
- for(const auto& cap : active_arms[0].captures)
- {
- bound_tts.insert( cap.binding_idx, cap.iterations, mv$(captures[cap.cap_idx]) );
- }
- return active_arms[0].index;
- ),
- (IfPat, BUG(sp, "IfPat unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- BUG(sp, "ExpectTok should have been handled already");
- ),
- (ExpectPat,
- struct H {
- static bool is_prefix(const ::std::vector<unsigned>& needle, const ::std::vector<unsigned>& haystack) {
- if( needle.size() > haystack.size() ) {
- return false;
- }
- else {
- for(unsigned int i = 0; i < needle.size(); i ++) {
- if(needle[i] != haystack[i])
- return false;
- }
- return true;
- }
- }
- };
-
- auto cap = Macro_HandlePatternCap(lex, e.type);
-
- unsigned int cap_idx = captures.size();
- captures.push_back( mv$(cap) );
- for(unsigned int i = 0; i < active_arms.size(); i ++)
- {
- auto& arm = active_arms[i];
- const auto& pat_e = arm_pats[i].as_ExpectPat();
- arm.captures.push_back( Capture { pat_e.idx, arm.stream.get_loop_iters(), cap_idx } );
- }
- )
- )
- }
-
- // Keep looping - breakout is handled in 'End' above
- }
-}
-#endif
void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std::vector<MacroExpansionEnt>& contents)
{
@@ -2438,7 +1982,7 @@ Token MacroExpander::realGetToken()
DEBUG("Crate name hack");
if( m_crate_name != "" )
{
- m_next_token = Token(TOK_STRING, m_crate_name);
+ m_next_token = Token(TOK_STRING, ::std::string(m_crate_name.c_str()));
return Token(TOK_DOUBLE_COLON);
}
break;
diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp
index c04e3548..05b1e065 100644
--- a/src/macro_rules/macro_rules.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -18,6 +18,7 @@
#include <set>
class MacroExpander;
+class SimplePatEnt;
TAGGED_UNION(MacroExpansionEnt, Token,
// TODO: have a "raw" stream instead of just tokens
@@ -40,8 +41,9 @@ extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x
/// Matching pattern entry
struct MacroPatEnt
{
- ::std::string name;
+ RcString name;
unsigned int name_index = 0;
+ // TODO: Include a point span for the token?
Token tok;
::std::vector<MacroPatEnt> subpats;
@@ -60,6 +62,8 @@ struct MacroPatEnt
PAT_BLOCK,
PAT_META,
PAT_ITEM, // :item
+ PAT_VIS,
+ PAT_LIFETIME,
} type;
MacroPatEnt():
@@ -73,7 +77,7 @@ struct MacroPatEnt
{
}
- MacroPatEnt(::std::string name, unsigned int name_index, Type type):
+ MacroPatEnt(RcString name, unsigned int name_index, Type type):
name( mv$(name) ),
name_index( name_index ),
tok(),
@@ -93,21 +97,55 @@ struct MacroPatEnt
friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x);
};
+struct SimplePatIfCheck
+{
+ MacroPatEnt::Type ty; // If PAT_TOKEN, token is checked
+ Token tok;
+};
+
+/// Simple pattern entry for macro_rules! arm patterns
+TAGGED_UNION( SimplePatEnt, End,
+ // End of the pattern stream (expects EOF, and terminates the match process)
+ (End, struct{}),
+ (LoopStart, struct{}),
+ (LoopNext, struct{}),
+ (LoopEnd, struct{}),
+ (Jump, struct {
+ size_t jump_target;
+ }),
+ // Expect a specific token, erroring/failing the arm if nt met
+ (ExpectTok, Token),
+ // Expect a pattern match
+ (ExpectPat, struct {
+ MacroPatEnt::Type type;
+ unsigned int idx;
+ }),
+ // Compare the head of the input stream and poke the pattern stream
+ (If, struct {
+ bool is_equal;
+ size_t jump_target;
+ ::std::vector<SimplePatIfCheck> ents;
+ })
+ );
+
+extern::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x);
+
/// An expansion arm within a macro_rules! blcok
struct MacroRulesArm
{
/// Names for the parameters
- ::std::vector< ::std::string> m_param_names;
+ ::std::vector<RcString> m_param_names;
/// Patterns
- ::std::vector<MacroPatEnt> m_pattern;
+ ::std::vector<SimplePatEnt> m_pattern;
/// Rule contents
::std::vector<MacroExpansionEnt> m_contents;
+ ~MacroRulesArm();
MacroRulesArm()
{}
- MacroRulesArm(::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
+ MacroRulesArm(::std::vector<SimplePatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
m_pattern( mv$(pattern) ),
m_contents( mv$(contents) )
{}
@@ -126,7 +164,7 @@ public:
/// Crate that defined this macro
/// - Populated on deserialise if not already set
- ::std::string m_source_crate;
+ RcString m_source_crate;
Ident::Hygiene m_hygiene;
@@ -143,4 +181,8 @@ public:
extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod);
extern MacroRulesPtr Parse_MacroRules(TokenStream& lex);
+extern ::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector<RcString>& names);
+extern ::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector<RcString>& var_names, ::std::map<unsigned int,bool>* var_set_ptr=nullptr);
+extern MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents);
+
#endif // MACROS_HPP_INCLUDED
diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp
index f9754286..2ad325b8 100644
--- a/src/macro_rules/mod.cpp
+++ b/src/macro_rules/mod.cpp
@@ -156,6 +156,17 @@ bool is_token_item(eTokenType tt) {
return false;
}
}
+bool is_token_vis(eTokenType tt) {
+ switch(tt)
+ {
+ case TOK_RWORD_PUB:
+ case TOK_RWORD_CRATE:
+ case TOK_INTERPOLATED_VIS:
+ return true;
+ default:
+ return true; // TODO: Is this true? it can capture just nothing
+ }
+}
MacroRulesPtr::MacroRulesPtr(MacroRules* p):
m_ptr(p)
@@ -177,7 +188,7 @@ MacroRulesPtr::~MacroRulesPtr()
switch(x.type)
{
case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break;
- case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break;
+ case MacroPatEnt::PAT_LOOP: os << "loop" << x.name << " w/ " << x.tok << " [" << x.subpats << "]"; break;
default:
os << "$" << x.name << ":";
switch(x.type)
@@ -194,6 +205,8 @@ MacroRulesPtr::~MacroRulesPtr()
case MacroPatEnt::PAT_BLOCK: os << "block"; break;
case MacroPatEnt::PAT_META: os << "meta"; break;
case MacroPatEnt::PAT_ITEM: os << "item"; break;
+ case MacroPatEnt::PAT_VIS: os << "vis"; break;
+ case MacroPatEnt::PAT_LIFETIME: os << "lifetime"; break;
}
break;
}
@@ -215,6 +228,39 @@ MacroRulesPtr::~MacroRulesPtr()
case MacroPatEnt::PAT_BLOCK: os << "PAT_BLOCK"; break;
case MacroPatEnt::PAT_META: os << "PAT_META"; break;
case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break;
+ case MacroPatEnt::PAT_VIS: os << "PAT_VIS"; break;
+ case MacroPatEnt::PAT_LIFETIME: os << "PAT_LIFETIME"; break;
+ }
+ return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x)
+{
+ TU_MATCH_HDRA( (x), { )
+ TU_ARMA(End, _e) os << "End";
+ TU_ARMA(LoopStart, _e) os << "LoopStart";
+ TU_ARMA(LoopNext, _e) os << "LoopNext";
+ TU_ARMA(LoopEnd, _e) os << "LoopEnd";
+ TU_ARMA(Jump, e) {
+ os << "Jump(->" << e.jump_target << ")";
+ }
+ TU_ARMA(ExpectTok, e) {
+ os << "Expect(" << e << ")";
+ }
+ TU_ARMA(ExpectPat, e) {
+ os << "Expect($" << e.idx << " = " << e.type << ")";
+ }
+ TU_ARMA(If, e) {
+ os << "If(" << (e.is_equal ? "=" : "!=") << "[";
+ for(const auto& p : e.ents) {
+ if(p.ty == MacroPatEnt::PAT_TOKEN)
+ os << p.tok;
+ else
+ os << p.ty;
+ os << ", ";
+ }
+ os << "] ->" << e.jump_target << ")";
+ }
}
return os;
}
@@ -243,4 +289,7 @@ MacroRulesPtr::~MacroRulesPtr()
MacroRules::~MacroRules()
{
}
+MacroRulesArm::~MacroRulesArm()
+{
+}
diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp
index 0cc7b3a8..6a476ef1 100644
--- a/src/macro_rules/parse.cpp
+++ b/src/macro_rules/parse.cpp
@@ -12,17 +12,25 @@
#include "pattern_checks.hpp"
MacroRulesPtr Parse_MacroRules(TokenStream& lex);
+namespace {
+ ::std::vector<SimplePatEnt> macro_pattern_to_simple(const Span& sp, const ::std::vector<MacroPatEnt>& pattern);
+}
/// A rule within a macro_rules! blcok
class MacroRule
{
public:
::std::vector<MacroPatEnt> m_pattern;
+ Span m_pat_span;
::std::vector<MacroExpansionEnt> m_contents;
+
+ MacroRule() {}
+ MacroRule(MacroRule&&) = default;
+ MacroRule(const MacroRule&) = delete;
};
/// Parse the pattern of a macro_rules! arm
-::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names)
+::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector<RcString>& names)
{
TRACE_FUNCTION;
Token tok;
@@ -32,6 +40,7 @@ public:
int depth = 0;
while( GET_TOK(tok, lex) != close || depth > 0 )
{
+ DEBUG("tok = " << tok);
if( tok.type() == open )
{
depth ++;
@@ -49,13 +58,14 @@ public:
switch( GET_TOK(tok, lex) )
{
// TODO: Allow any reserved word
- case TOK_RWORD_TYPE:
- case TOK_RWORD_PUB:
+ default:
+ if( !(TOK_RWORD_PUB <= tok.type() && tok.type() <= TOK_RWORD_UNSIZED) )
+ throw ParseError::Unexpected(lex, tok);
case TOK_IDENT: {
- ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok);
+ auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok));
GET_CHECK_TOK(tok, lex, TOK_COLON);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string type = mv$(tok.str());
+ RcString type = tok.istr();
unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin();
if( idx == names.size() )
@@ -83,6 +93,10 @@ public:
ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) );
else if( type == "item" )
ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) );
+ else if( /*TARGETVER_1_29 && */ type == "vis" ) // TODO: Should this be selective?
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_VIS) );
+ else if( /*TARGETVER_1_29 && */ type == "lifetime" ) // TODO: Should this be selective?
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_LIFETIME) );
else
ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'");
break; }
@@ -111,8 +125,6 @@ public:
throw ParseError::Unexpected(lex, tok);
}
break; }
- default:
- throw ParseError::Unexpected(lex, tok);
}
break;
case TOK_EOF:
@@ -130,8 +142,8 @@ public:
::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(
TokenStream& lex,
enum eTokenType open, enum eTokenType close,
- const ::std::vector< ::std::string>& var_names,
- ::std::map<unsigned int,bool>* var_set_ptr=nullptr
+ const ::std::vector<RcString>& var_names,
+ ::std::map<unsigned int,bool>* var_set_ptr/*=nullptr*/
)
{
TRACE_FUNCTION;
@@ -200,13 +212,16 @@ 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);
+ auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok));
unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin();
if( idx == var_names.size() ) {
// TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar.
@@ -222,10 +237,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);
@@ -259,8 +270,12 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
throw ParseError::Unexpected(lex, tok);
}
// - Pattern entries
- ::std::vector< ::std::string> names;
- rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names);
+ ::std::vector<RcString> names;
+ {
+ auto ps = lex.start_span();
+ rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names);
+ rule.m_pat_span = lex.end_span(ps);
+ }
GET_CHECK_TOK(tok, lex, TOK_FATARROW);
@@ -279,164 +294,9 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
return rule;
}
-bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEnt& right)
-{
- if( left.type > right.type )
- return patterns_are_same(sp, right, left);
-
- //if( left.name != right.name ) {
- // TODO(sp, "Handle different binding names " << left << " != " << right);
- //}
-
- // NOTE: left.type <= right.type
- switch(right.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- assert( left.type == MacroPatEnt::PAT_TOKEN );
- return right.tok == left.tok;
- case MacroPatEnt::PAT_LOOP:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- // - Check for compatibility, but these two don't match
- if( patterns_are_same(sp, left, right.subpats.at(0)) == true )
- ERROR(sp, E0000, "Incompatible use of loop with matching non-loop");
- return false;
- case MacroPatEnt::PAT_LOOP:
- TODO(sp, "patterns_are_same - PAT_LOOP");
- default:
- assert( !"" );
- }
-
- case MacroPatEnt::PAT_TT:
- if( left.type == right.type )
- return true;
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- break;
-
- case MacroPatEnt::PAT_PAT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- // - If this token is a valid pattern token, error
- if( is_token_pat(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_PAT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- }
- break;
- // `:ident` - Compatible with just other tokens
- case MacroPatEnt::PAT_IDENT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_IDENT )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_IDENT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_PATH:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_path(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_PATH:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_TYPE:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_type(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_TYPE:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_EXPR:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_expr(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- // TODO: Allow a loop starting with an expr?
- // - Consume, add split based on loop condition or next arm
- // - Possible problem with binding levels.
- case MacroPatEnt::PAT_EXPR:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_STMT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_stmt(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_STMT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- // Block - Expects '{' - Compatible with everything but a literal '{'
- case MacroPatEnt::PAT_BLOCK:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_BRACE_OPEN )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_BLOCK:
- return true;
- default:
- return false;
- }
- // Matches meta/attribute fragments.
- case MacroPatEnt::PAT_META:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_IDENT )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_META:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- // Matches items
- case MacroPatEnt::PAT_ITEM:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_item(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_ITEM:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- }
- throw "";
-}
-
// TODO: Also count the number of times each variable is used?
-void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::std::string>& names) {
+void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector<RcString>& names)
+{
for( const auto& pat : pats )
{
if( pat.type == MacroPatEnt::PAT_LOOP ) {
@@ -452,6 +312,15 @@ void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::st
}
}
+MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents)
+{
+ // - Convert the rule into an instruction stream
+ auto rule_sequence = macro_pattern_to_simple(pat_sp, pattern);
+ auto arm = MacroRulesArm( mv$(rule_sequence), mv$(contents) );
+ enumerate_names(pattern, arm.m_param_names);
+ return arm;
+}
+
/// Parse an entire macro_rules! block into a format that exec.cpp can use
MacroRulesPtr Parse_MacroRules(TokenStream& lex)
{
@@ -478,11 +347,7 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex)
// Re-parse the patterns into a unified form
for(auto& rule : rules)
{
- MacroRulesArm arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) );
-
- enumerate_names(arm.m_pattern, arm.m_param_names);
-
- rule_arms.push_back( mv$(arm) );
+ rule_arms.push_back( Parse_MacroRules_MakeArm(rule.m_pat_span, mv$(rule.m_pattern), mv$(rule.m_contents)) );
}
auto rv = new MacroRules( );
@@ -491,3 +356,287 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex)
return MacroRulesPtr(rv);
}
+
+namespace {
+
+ struct ExpTok {
+ MacroPatEnt::Type ty;
+ const Token* tok;
+ ExpTok(MacroPatEnt::Type ty, const Token* tok): ty(ty), tok(tok) {}
+ bool operator==(const ExpTok& t) const { return this->ty == t.ty && *this->tok == *t.tok; }
+ };
+ ::std::ostream& operator<<(::std::ostream& os, const ExpTok& t) {
+ os << "ExpTok(" << t.ty << " " << *t.tok << ")";
+ return os;
+ }
+
+ // Yields all possible ExpectTok/ExpectPat entries from a pattern position
+ // Returns `true` if there's no fall-through
+ bool macro_pattern_get_head_set_inner(::std::vector<ExpTok>& rv, const ::std::vector<MacroPatEnt>& pattern, size_t direct_pos, size_t indirect_ofs)
+ {
+ for(size_t idx = direct_pos; idx < pattern.size(); idx ++)
+ {
+ const auto& ent = pattern[idx];
+ switch(ent.type)
+ {
+ case MacroPatEnt::PAT_LOOP:
+ if( macro_pattern_get_head_set_inner(rv, ent.subpats, 0, indirect_ofs) )
+ {
+ // + loops have to iterate at least once, so if the set is closed by the sub-patterns, close us too
+ if(ent.name == "+")
+ {
+ return true;
+ }
+ // for * and ? loops, they can be skipped entirely.
+ // - No separator, this is for the skip case
+ }
+ else
+ {
+ // If the inner pattern didn't close the option set, then the next token can be the separator
+ if( ent.tok != TOK_NULL )
+ {
+ // If indirect is non-zero, decrement without doing anything
+ if( indirect_ofs > 0 )
+ {
+ indirect_ofs --;
+ }
+ else
+ {
+ rv.push_back(ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok));
+ }
+ }
+ }
+ break;
+ default:
+ // If indirect is non-zero, decrement
+ if( indirect_ofs > 0 )
+ {
+ indirect_ofs --;
+ }
+ else
+ {
+ rv.push_back( ExpTok(ent.type, &ent.tok) );
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ ::std::vector<ExpTok> macro_pattern_get_head_set(const ::std::vector<MacroPatEnt>& pattern, size_t direct_pos, size_t indirect_ofs)
+ {
+ ::std::vector<ExpTok> rv;
+ macro_pattern_get_head_set_inner(rv, pattern, direct_pos, indirect_ofs);
+ return rv;
+ }
+
+ void macro_pattern_to_simple_inner(const Span& sp, ::std::vector<SimplePatEnt>& rv, const ::std::vector<MacroPatEnt>& pattern)
+ {
+ size_t level_start = rv.size();
+ TRACE_FUNCTION_FR("[" << pattern << "]", "[" << FMT_CB(ss, for(auto it = rv.begin()+level_start; it != rv.end(); ++it) { ss << *it << ", "; }) << "]");
+ auto push = [&rv](SimplePatEnt spe) {
+ DEBUG("[macro_pattern_to_simple_inner] rv[" << rv.size() << "] = " << spe);
+ rv.push_back( ::std::move(spe) );
+ };
+ auto push_ifv = [&push](bool is_equal, ::std::vector<SimplePatIfCheck> ents, size_t tgt) {
+ push(SimplePatEnt::make_If({ is_equal, tgt, mv$(ents) }));
+ };
+ auto push_if = [&push_ifv](bool is_equal, MacroPatEnt::Type ty, const Token& tok, size_t tgt) {
+ push_ifv(is_equal, make_vec1(SimplePatIfCheck { ty, tok }), tgt);
+ };
+ for(size_t idx = 0; idx < pattern.size(); idx ++)
+ {
+ const auto& ent = pattern[idx];
+ DEBUG("[" << idx << "] ent = " << ent);
+ switch(ent.type)
+ {
+ case MacroPatEnt::PAT_LOOP: {
+ auto entry_pats = macro_pattern_get_head_set(ent.subpats, 0, 0);
+ DEBUG("Entry = [" << entry_pats << "]");
+ ASSERT_BUG(sp, entry_pats.size() > 0, "No entry conditions extracted from sub-pattern [" << ent.subpats << "]");
+ auto skip_pats = macro_pattern_get_head_set(pattern, idx+1, 0);
+ DEBUG("Skip = [" << skip_pats << "]");
+
+ // - Duplicates need special handling (build up a subseqent set)
+ for(const auto& ee : entry_pats)
+ {
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ee) != skip_pats.end() )
+ {
+ TODO(sp, "Entry and skip patterns share an entry, ambigious - " << ee);
+ }
+ }
+
+ // TODO: Combine the two cases below into one
+
+ // If the loop is a $()+ loop, then just recurse into it
+ if( ent.name == "+" )
+ {
+ push( SimplePatEnt::make_LoopStart({}) );
+ size_t start = rv.size();
+ macro_pattern_to_simple_inner(sp, rv, ent.subpats);
+ push( SimplePatEnt::make_LoopNext({}) );
+ size_t rewrite_start = rv.size();
+ if( ent.tok != TOK_NULL )
+ {
+ // If the loop terminator is also valid after the loop
+ // - Terminate the loop if the next two tokens aren't `<SEP>` folled by any of `<ENTRY>`
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) {
+ size_t expect_and_jump_pos = rv.size() + entry_pats.size() + 1;
+ for(const auto& p : entry_pats)
+ {
+ auto v = ::make_vec2<SimplePatIfCheck>(
+ { MacroPatEnt::PAT_TOKEN, ent.tok},
+ { p.ty, *p.tok }
+ );
+ // Jump if equal
+ push_ifv(true, mv$(v), expect_and_jump_pos);
+ }
+ // If any of the above succeeded, they'll jump past this jump
+ push( SimplePatEnt::make_Jump({ ~0u }) );
+ }
+ else {
+ size_t end = rv.size() + 3;
+ push_if( false, MacroPatEnt::PAT_TOKEN, ent.tok, end );
+ }
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ push( SimplePatEnt::make_Jump({ start }) );
+ }
+ else
+ {
+ // TODO: What if there's a collision at this level?
+ for(const auto& p : entry_pats)
+ {
+ push_if(true, p.ty, *p.tok, start);
+ }
+ }
+
+ size_t post_loop = rv.size();
+ for(size_t i = rewrite_start; i < post_loop; i++)
+ {
+ if( auto* pe = rv[i].opt_If() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ if( auto* pe = rv[i].opt_Jump() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ }
+ push( SimplePatEnt::make_LoopEnd({}) );
+ }
+ else
+ {
+ push( SimplePatEnt::make_LoopStart({}) );
+
+ // Options:
+ // - Enter the loop (if the next token is one of the head set of the loop)
+ // - Skip the loop (the next token is the head set of the subsequent entries)
+ size_t rewrite_start = rv.size();
+ if( ent.name != "+" )
+ {
+ if( entry_pats.size() == 1 )
+ {
+ // If not the entry pattern, skip.
+ push_if(false, entry_pats.front().ty, *entry_pats.front().tok, ~0u);
+ }
+ else if( skip_pats.empty() )
+ {
+ // No skip patterns, try all entry patterns
+ size_t start = rv.size() + entry_pats.size() + 1;
+ for(const auto& p : entry_pats)
+ {
+ push_if(true, p.ty, *p.tok, start);
+ }
+ push(SimplePatEnt::make_Jump({ ~0u }));
+ }
+ else
+ {
+ for(const auto& p : skip_pats)
+ {
+ push_if(true, p.ty, *p.tok, ~0u);
+ }
+ }
+ }
+
+ macro_pattern_to_simple_inner(sp, rv, ent.subpats);
+ push( SimplePatEnt::make_LoopNext({}) );
+
+ if( ent.name != "?" )
+ {
+ if( ent.tok != TOK_NULL )
+ {
+ // If the joiner is also valid after the loop, handle by also checking the entry conditions
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) {
+ // Try all re-loop (joiner + entry) patterns, if any fail then jump to the end.
+ for(const auto& p : entry_pats) {
+ auto v = ::make_vec2<SimplePatIfCheck>(
+ { MacroPatEnt::PAT_TOKEN, ent.tok},
+ { p.ty, *p.tok }
+ );
+ push_ifv(false, mv$(v), ~0u);
+ }
+ }
+ else {
+ // If not the joiner, jump to the end
+ push_if(false, MacroPatEnt::PAT_TOKEN, ent.tok, ~0u);
+ }
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ }
+ // Jump back to the entry check.
+ push(SimplePatEnt::make_Jump({ rewrite_start }));
+ }
+ else
+ {
+ ASSERT_BUG(sp, ent.tok == TOK_NULL, "$()? with a separator isn't valid");
+ }
+ size_t post_loop = rv.size();
+ for(size_t i = rewrite_start; i < post_loop; i++)
+ {
+ if( auto* pe = rv[i].opt_If() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ if( auto* pe = rv[i].opt_Jump() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ }
+ push( SimplePatEnt::make_LoopEnd({}) );
+ }
+ } break;
+ case MacroPatEnt::PAT_TOKEN:
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ break;
+ default:
+ push( SimplePatEnt::make_ExpectPat({ ent.type, ent.name_index }) );
+ break;
+ }
+ }
+
+ for(size_t i = level_start; i < rv.size(); i ++)
+ {
+ TU_MATCH_HDRA( (rv[i]), { )
+ default:
+ // Ignore
+ TU_ARMA(If, e) {
+ ASSERT_BUG(sp, e.jump_target < rv.size(), "If target out of bounds, " << e.jump_target << " >= " << rv.size());
+ }
+ TU_ARMA(Jump, e) {
+ ASSERT_BUG(sp, e.jump_target < rv.size(), "Jump target out of bounds, " << e.jump_target << " >= " << rv.size());
+ }
+ }
+ }
+ }
+
+ ::std::vector<SimplePatEnt> macro_pattern_to_simple(const Span& sp, const ::std::vector<MacroPatEnt>& pattern)
+ {
+ ::std::vector<SimplePatEnt> rv;
+ TRACE_FUNCTION_FR(pattern, rv);
+ macro_pattern_to_simple_inner(sp, rv, pattern);
+ return rv;
+ }
+}
diff --git a/src/macro_rules/pattern_checks.hpp b/src/macro_rules/pattern_checks.hpp
index 4ebbe915..6ce15050 100644
--- a/src/macro_rules/pattern_checks.hpp
+++ b/src/macro_rules/pattern_checks.hpp
@@ -13,3 +13,4 @@ extern bool is_token_type(eTokenType tt);
extern bool is_token_expr(eTokenType tt);
extern bool is_token_stmt(eTokenType tt);
extern bool is_token_item(eTokenType tt);
+extern bool is_token_vis(eTokenType tt);
diff --git a/src/main.cpp b/src/main.cpp
index a50fe095..d63d4041 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -34,6 +34,8 @@ bool g_debug_enabled = true;
::std::string g_cur_phase;
::std::set< ::std::string> g_debug_disable_map;
+TargetVersion gTargetVersion = TargetVersion::Rustc1_29;
+
void init_debug_list()
{
g_debug_disable_map.insert( "Target Load" );
@@ -51,6 +53,7 @@ void init_debug_list()
g_debug_disable_map.insert( "Resolve Type Aliases" );
g_debug_disable_map.insert( "Resolve Bind" );
+ g_debug_disable_map.insert( "Resolve UFCS Outer" );
g_debug_disable_map.insert( "Resolve UFCS paths" );
g_debug_disable_map.insert( "Resolve HIR Markings" );
g_debug_disable_map.insert( "Constant Evaluate" );
@@ -79,6 +82,7 @@ void init_debug_list()
g_debug_disable_map.insert( "HIR Serialise" );
g_debug_disable_map.insert( "Trans Enumerate" );
+ g_debug_disable_map.insert( "Trans Auto Impls" );
g_debug_disable_map.insert( "Trans Monomorph" );
g_debug_disable_map.insert( "MIR Optimise Inline" );
g_debug_disable_map.insert( "Trans Codegen" );
@@ -96,7 +100,6 @@ void init_debug_list()
{
s = ::std::string { debug_string, end };
debug_string = end + 1;
- g_debug_disable_map.erase( s );
}
else
{
@@ -239,6 +242,8 @@ int main(int argc, char *argv[])
Cfg_SetFlag("test");
}
+ Expand_Init();
+
try
{
// Parse the crate into AST
@@ -247,6 +252,7 @@ int main(int argc, char *argv[])
});
crate.m_test_harness = params.test_harness;
crate.m_crate_name_suffix = params.crate_name_suffix;
+ //crate.m_crate_name = params.crate_name;
if( params.last_stage == ProgramParams::STAGE_PARSE ) {
return 0;
@@ -263,6 +269,10 @@ int main(int argc, char *argv[])
crate.load_externs();
});
+ if( params.crate_name != "" ) {
+ crate.m_crate_name = params.crate_name;
+ }
+
// Iterate all items in the AST, applying syntax extensions
CompilePhaseV("Expand", [&]() {
Expand(crate);
@@ -331,7 +341,7 @@ int main(int argc, char *argv[])
switch( crate.m_crate_type )
{
case ::AST::Crate::Type::RustLib:
- params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".hir");
+ params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".rlib");
break;
case ::AST::Crate::Type::Executable:
params.outfile = FMT(params.output_dir << crate.m_crate_name);
@@ -363,9 +373,9 @@ int main(int argc, char *argv[])
if( crate.m_crate_type == ::AST::Crate::Type::Executable || params.test_harness || crate.m_crate_type == ::AST::Crate::Type::ProcMacro )
{
bool allocator_crate_loaded = false;
- ::std::string alloc_crate_name;
+ RcString alloc_crate_name;
bool panic_runtime_loaded = false;
- ::std::string panic_crate_name;
+ RcString panic_crate_name;
bool panic_runtime_needed = false;
for(const auto& ec : crate.m_extern_crates)
{
@@ -411,17 +421,15 @@ int main(int argc, char *argv[])
}
});
+ /// Emit the dependency files
if( params.emit_depfile != "" )
{
- ::std::ofstream of { params.emit_depfile };
- of << params.outfile << ":";
// - Iterate all loaded files for modules
- struct H {
- ::std::ofstream& of;
- H(::std::ofstream& of): of(of) {}
+ struct PathEnumerator {
+ ::std::vector<::std::string> out;
void visit_module(::AST::Module& mod) {
if( mod.m_file_info.path != "!" && mod.m_file_info.path.back() != '/' ) {
- of << " " << mod.m_file_info.path;
+ out.push_back( mod.m_file_info.path );
}
// TODO: Should we check anon modules?
//for(auto& amod : mod.anon_mods()) {
@@ -434,7 +442,19 @@ int main(int argc, char *argv[])
}
}
};
- H(of).visit_module(crate.m_root_module);
+ PathEnumerator pe;
+ pe.visit_module(crate.m_root_module);
+
+ ::std::ofstream of { params.emit_depfile };
+ // TODO: Escape spaces and colons in these paths
+ of << params.outfile << ": " << params.infile;
+ for(const auto& mod_path : pe.out)
+ {
+ of << " " << mod_path;
+ }
+ of << ::std::endl;
+
+ of << params.outfile << ":";
// - Iterate all loaded crates files
for(const auto& ec : crate.m_extern_crates)
{
@@ -476,6 +496,13 @@ int main(int argc, char *argv[])
});
// Deallocate the original crate
crate = ::AST::Crate();
+ if( params.debug.dump_hir )
+ {
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// Replace type aliases (`type`) into the actual type
// - Also inserts defaults in trait impls
@@ -490,6 +517,16 @@ int main(int argc, char *argv[])
CompilePhaseV("Resolve HIR Markings", [&]() {
ConvertHIR_Markings(*hir_crate);
});
+ // Determine what trait to use for <T>::Foo in outer scope
+ CompilePhaseV("Resolve UFCS Outer", [&]() {
+ ConvertHIR_ResolveUFCS_Outer(*hir_crate);
+ });
+ if( params.debug.dump_hir ) {
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// Determine what trait to use for <T>::Foo (and does some associated type expansion)
CompilePhaseV("Resolve UFCS paths", [&]() {
ConvertHIR_ResolveUFCS(*hir_crate);
@@ -651,6 +688,8 @@ int main(int argc, char *argv[])
crate_type = ::AST::Crate::Type::Executable;
}
+ // TODO: For 1.29 executables/dylibs, add oom/panic shims
+
// Enumerate items to be passed to codegen
TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() {
switch( crate_type )
@@ -671,6 +710,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
@@ -683,50 +727,43 @@ int main(int argc, char *argv[])
case ::AST::Crate::Type::Unknown:
throw "";
case ::AST::Crate::Type::RustLib:
- // Generate a loadable .o
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- // TODO: Link metatdata and object into a .rlib
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
+ CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile + ".hir", *hir_crate); });
+ // Generate a loadable .o
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::StaticLibrary, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break;
case ::AST::Crate::Type::RustDylib:
- // Generate a .so
- //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".so", trans_opt, *hir_crate, items, CodegenOutput::DynamicLibrary); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- // TODO: Add the metadata to the .so as a non-loadable segment
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::DynamicLibrary);
+ CompilePhaseV("HIR Serialise", [&]() {
+ //auto saved_ext_crates = ::std::move(hir_crate->m_ext_crates);
+ HIR_Serialise(params.outfile + ".hir", *hir_crate);
+ //hir_crate->m_ext_crates = ::std::move(saved_ext_crates);
+ });
+ // Generate a .so
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::DynamicLibrary, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break;
case ::AST::Crate::Type::CDylib:
// Generate a .so/.dll
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/false); });
- // - No metadata file
- //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::DynamicLibrary);
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::DynamicLibrary, trans_opt, *hir_crate, items, ""); });
break;
case ::AST::Crate::Type::ProcMacro: {
// Needs: An executable (the actual macro handler), metadata (for `extern crate foo;`)
- // 1. Generate code for the .o file
- // TODO: Is the .o actually needed for proc macros?
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
-
- // 2. Generate code for the plugin itself
- TransList items2 = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); });
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items2); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items2); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + "-plugin", trans_opt, *hir_crate, items2, /*is_executable=*/true); });
-
+ // 1. Generate code for the plugin itself
+ TransList items = CompilePhase<TransList>("Trans Enumerate PM", [&]() { return Trans_Enumerate_Main(*hir_crate); });
+ CompilePhaseV("Trans Auto Impls PM", [&]() { Trans_AutoImpls(*hir_crate, items); });
+ CompilePhaseV("Trans Monomorph PM", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
+ CompilePhaseV("MIR Optimise Inline PM", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
// - Save a very basic HIR dump, making sure that there's no lang items in it (e.g. `mrustc-main`)
- hir_crate->m_lang_items.clear();
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
- //Trans_Link(params.outfile+"-plugin", "", params.outfile + "-plugin.o", CodegenOutput::StaticLibrary);
+ CompilePhaseV("HIR Serialise", [&]() {
+ auto saved_lang_items = ::std::move(hir_crate->m_lang_items); hir_crate->m_lang_items.clear();
+ HIR_Serialise(params.outfile + ".hir", *hir_crate);
+ hir_crate->m_lang_items = ::std::move(saved_lang_items);
+ });
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::Executable, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break; }
case ::AST::Crate::Type::Executable:
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/true); });
- //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::Executable);
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::Executable, trans_opt, *hir_crate, items, ""); });
break;
}
}
@@ -961,7 +998,14 @@ ProgramParams::ProgramParams(int argc, char *argv[])
exit(0);
}
else if( strcmp(arg, "--version" ) == 0 ) {
- ::std::cout << "MRustC " << Version_GetString() << ::std::endl;
+ const char* rustc_target = "unknown";
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19: rustc_target = "1.19"; break;
+ case TargetVersion::Rustc1_29: rustc_target = "1.29"; break;
+ }
+ // NOTE: Starts the version with "rustc 1.29.100" so build scripts don't get confused
+ ::std::cout << "rustc " << rustc_target << ".100 (mrustc " << Version_GetString() << ")" << ::std::endl;
::std::cout << "- Build time: " << gsVersion_BuildTime << ::std::endl;
::std::cout << "- Commit: " << gsVersion_GitHash << (gbVersion_GitDirty ? " (dirty tree)" : "") << ::std::endl;
exit(0);
@@ -1024,6 +1068,9 @@ ProgramParams::ProgramParams(int argc, char *argv[])
if( strcmp(type_str, "rlib") == 0 ) {
this->crate_type = ::AST::Crate::Type::RustLib;
}
+ else if( strcmp(type_str, "dylib") == 0 ) {
+ this->crate_type = ::AST::Crate::Type::RustDylib;
+ }
else if( strcmp(type_str, "bin") == 0 ) {
this->crate_type = ::AST::Crate::Type::Executable;
}
@@ -1094,6 +1141,19 @@ ProgramParams::ProgramParams(int argc, char *argv[])
}
}
+
+ if( const auto* a = getenv("MRUSTC_TARGET_VER") )
+ {
+ if( strcmp(a, "1.19") == 0 ) {
+ gTargetVersion = TargetVersion::Rustc1_19;
+ }
+ else if( strcmp(a, "1.29") == 0 ) {
+ gTargetVersion = TargetVersion::Rustc1_29;
+ }
+ else {
+ }
+ }
+
if( const auto* a = getenv("MRUSTC_DUMP") )
{
while( a[0] )
diff --git a/src/mir/check.cpp b/src/mir/check.cpp
index b2d86590..d159c85f 100644
--- a/src/mir/check.cpp
+++ b/src/mir/check.cpp
@@ -19,7 +19,6 @@ namespace {
if( const auto* tep = unsized_ty.m_data.opt_TraitObject() )
{
const auto& trait_path = tep->m_trait;
- const auto& trait = *tep->m_trait.m_trait_ptr;
if( trait_path.m_path.m_path == ::HIR::SimplePath() )
{
@@ -27,8 +26,10 @@ namespace {
}
else
{
- auto vtable_ty_spath = trait_path.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& trait = *tep->m_trait.m_trait_ptr;
+
+ const auto& vtable_ty_spath = trait.m_vtable_path;
+ MIR_ASSERT(state, vtable_ty_spath != ::HIR::SimplePath(), "Trait with no vtable - " << trait_path);
const auto& vtable_ref = state.m_resolve.m_crate.get_struct_by_path(state.sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone();
@@ -115,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
{
}
+ explicit ValStates(const ValStates& v) = default;
+ ValStates(ValStates&& v) = default;
+ ValStates& operator=(const ValStates& v) = delete;
+ ValStates& operator=(ValStates&& v) = default;
+
void fmt(::std::ostream& os) {
os << "ValStates { ";
switch(ret_state)
@@ -158,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
return locals.empty() && args.empty();
}
+ // NOTE: Moves if this state is empty
bool merge(unsigned bb_idx, ValStates& other)
{
DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);));
if( this->empty() )
{
- *this = other;
+ *this = ValStates(other);
return true;
}
else if( *this == other )
@@ -182,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid)
{
- TU_MATCH_DEF( ::MIR::LValue, (lv), (e),
- (
- ),
+ if( !lv.m_wrappers.empty())
+ {
+ return ;
+ }
+ TU_MATCHA( (lv.m_root), (e),
(Return,
ret_state = is_valid ? State::Valid : State::Invalid;
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range");
- DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
- this->args[e.idx] = is_valid ? State::Valid : State::Invalid;
+ MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv);
+ DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid"));
+ this->args[e] = is_valid ? State::Valid : State::Invalid;
),
(Local,
- MIR_ASSERT(state, e < this->locals.size(), "Local index out of range");
+ MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv);
DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid"));
this->locals[e] = is_valid ? State::Valid : State::Invalid;
+ ),
+ (Static,
)
)
}
void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
- TU_MATCH( ::MIR::LValue, (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
if( this->ret_state != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range");
- if( this->args[e.idx] != State::Valid )
+ MIR_ASSERT(state, e < this->args.size(), "Arg index out of range");
+ if( this->args[e] != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Local,
@@ -218,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Static,
- ),
- (Field,
- ensure_valid(state, *e.val);
- ),
- (Deref,
- ensure_valid(state, *e.val);
- ),
- (Index,
- ensure_valid(state, *e.val);
- ensure_valid(state, *e.idx);
- ),
- (Downcast,
- ensure_valid(state, *e.val);
)
)
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ if( this->locals[w.as_Index()] != State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index()));
+ }
+ }
}
void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
ensure_valid(state, lv);
- ::HIR::TypeRef tmp;
- if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) )
+ if( ! state.lvalue_is_copy(lv) )
{
mark_validity(state, lv, false);
}
@@ -283,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
::std::vector<unsigned int> path;
ValStates state;
};
+ // TODO: Remove this? The path is useful, but the cloned states are really expensive
+ // - Option: Keep the paths, but only ever use the pre-set entry state?
::std::vector<ToVisit> to_visit_blocks;
// TODO: Check that all used locals are also set (anywhere at all)
- auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, auto vs) {
+ auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs, bool can_move) {
for(const auto& b : to_visit_blocks)
if( b.bb == idx && b.state == vs)
return ;
if( block_start_states.at(idx) == vs )
return ;
src_path.push_back(idx);
- to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } );
+ // TODO: Update the target block, and only visit if we've induced a change
+ to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } );
+ };
+ auto add_to_visit_move = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates vs) {
+ add_to_visit(idx, mv$(src_path), vs, true);
+ };
+ auto add_to_visit_copy = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs) {
+ add_to_visit(idx, mv$(src_path), vs, false);
};
- add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
+ add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
while( to_visit_blocks.size() > 0 )
{
auto block = to_visit_blocks.back().bb;
@@ -310,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
if( ! block_start_states.at(block).merge(block, val_state) ) {
continue ;
}
- DEBUG("BB" << block << " via [" << path << "]");
+ ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), "");
+ DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);));
// 2. Using the newly merged state, iterate statements checking the usage and updating state.
const auto& bb = fcn.blocks[block];
@@ -341,6 +357,18 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
val_state.mark_validity( state, v.second, true );
break;
case ::MIR::Statement::TAG_Assign:
+ // Destination must be valid
+ for(const auto& w : stmt.as_Assign().dst.m_wrappers)
+ {
+ if( w.is_Deref() ) {
+ // TODO: Check validity of the rest of the wrappers.
+ }
+ if( w.is_Index() )
+ {
+ if( val_state.locals[w.as_Index()] != ValStates::State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index()));
+ }
+ }
// Check source (and invalidate sources)
TU_MATCH( ::MIR::RValue, (stmt.as_Assign().src), (se),
(Use,
@@ -410,13 +438,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// 3. Pass new state on to destination blocks
state.set_cur_stmt_term(block);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
+ TU_MATCH_HDRA( (bb.terminator), { )
+ TU_ARMA(Incomplete, e) {
// Should be impossible here.
- ),
- (Return,
+ }
+ TU_ARMA(Return, e) {
// Check if the return value has been set
- val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) );
+ val_state.ensure_valid( state, ::MIR::LValue::new_Return() );
// Ensure that no other non-Copy values are valid
for(unsigned int i = 0; i < val_state.locals.size(); i ++)
{
@@ -431,51 +459,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// TODO: Error, becuase this has just been leaked
}
}
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, e) {
// TODO: Ensure that cleanup has been performed.
- ),
- (Goto,
+ }
+ TU_ARMA(Goto, e) {
// Push block with the new state
- add_to_visit( e, mv$(path), mv$(val_state) );
- ),
- (Panic,
+ add_to_visit_move( e, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Panic, e) {
// What should be done here?
- ),
- (If,
+ }
+ TU_ARMA(If, e) {
// Push blocks
val_state.ensure_valid( state, e.cond );
- add_to_visit( e.bb0, path, val_state );
- add_to_visit( e.bb1, mv$(path), mv$(val_state) );
- ),
- (Switch,
+ add_to_visit_copy( e.bb0, path, val_state );
+ add_to_visit_move( e.bb1, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Switch, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) );
+ }
}
- ),
- (SwitchValue,
+ TU_ARMA(SwitchValue, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit_copy( tgt, path, val_state );
}
- add_to_visit( e.def_target, path, val_state );
- ),
- (Call,
+ add_to_visit_move( e.def_target, path, mv$(val_state) );
+ }
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
val_state.ensure_valid( state, e.fcn.as_Value() );
for(const auto& arg : e.args)
val_state.move_val( state, arg );
// Push blocks (with return valid only in one)
- add_to_visit(e.panic_block, path, val_state);
+ add_to_visit_copy(e.panic_block, path, val_state);
// TODO: If the function returns !, don't follow the ret_block
val_state.mark_validity( state, e.ret_val, true );
- add_to_visit(e.ret_block, mv$(path), mv$(val_state));
- )
- )
+ add_to_visit_move(e.ret_block, mv$(path), mv$(val_state));
+ }
+ }
}
}
@@ -686,10 +714,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// TODO: Check that the input type is Copy
),
(Borrow,
- // TODO: Check return type
+ ::HIR::TypeRef tmp;
+ check_types( dst_ty, ::HIR::TypeRef::new_borrow(e.type, state.get_lvalue_type(tmp, e.val).clone()) );
),
(Cast,
- // TODO: Check return type
+ // Check return type
+ check_types( dst_ty, e.type );
// TODO: Check suitability of source type (COMPLEX)
),
(BinOp,
@@ -835,33 +865,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
state.set_cur_stmt_term(bb_idx);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
- ),
- (Return,
+ TU_MATCH_HDRA( (bb.terminator), {)
+ TU_ARMA(Incomplete, e) {
+ }
+ TU_ARMA(Return, e) {
// TODO: Check if the function can return (i.e. if its return type isn't an empty type)
- ),
- (Diverge,
- ),
- (Goto,
- ),
- (Panic,
- ),
- (If,
+ }
+ TU_ARMA(Diverge, e) {
+ }
+ TU_ARMA(Goto, e) {
+ }
+ TU_ARMA(Panic, e) {
+ }
+ TU_ARMA(If, e) {
// Check that condition lvalue is a bool
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, e.cond);
if( ty != ::HIR::CoreType::Bool ) {
MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty);
}
- ),
- (Switch,
+ }
+ TU_ARMA(Switch, e) {
// Check that the condition is an enum
- ),
- (SwitchValue,
+ }
+ TU_ARMA(SwitchValue, e) {
// Check that the condition's type matches the values
- ),
- (Call,
+ }
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
{
::HIR::TypeRef tmp;
@@ -872,8 +902,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
}
}
// Typecheck arguments and return value
- )
- )
+ }
+ }
}
}
diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp
index 24a4930a..0cc83c6f 100644
--- a/src/mir/check_full.cpp
+++ b/src/mir/check_full.cpp
@@ -446,68 +446,54 @@ namespace
}
const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
{
- TU_MATCHA( (lv), (e),
+ const State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return return_value;
+ state_p = &return_value;
),
(Argument,
- return args.at(e.idx);
+ state_p = &args.at(e);
),
(Local,
- return locals.at(e);
+ state_p = &locals.at(e);
),
(Static,
static State state_of_static(true);
return state_of_static;
- ),
- (Field,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs);
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- return states[e.field_index];
- }
- else
- {
- return vs;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( state_p->is_composite() ) {
+ break;
}
- ),
- (Deref,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
+ const auto& vs = *state_p;
+ state_p = nullptr;
+
+ TU_MATCHA( (w), (e),
+ (Field,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, e < states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
MIR_TODO(mir_res, "Deref with composite state");
- }
- else
- {
- return vs;
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- //return State(vs_v.is_valid() && vs_i.is_valid());
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
- return vs_v;
- ),
- (Downcast,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- if( vs_v.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs_v);
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v));
- return states[0];
- }
- else
- {
- return vs_v;
- }
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
+ MIR_BUG(mir_res, "Indexing a composite state");
+ ),
+ (Downcast,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs));
+ state_p = &states[0];
+ )
)
- )
- throw "";
+ assert(state_p);
+ }
+ return *state_p;
}
void clear_state(const ::MIR::TypeResolve& mir_res, State& s) {
@@ -522,42 +508,47 @@ namespace
void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs)
{
TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")");
- TU_MATCHA( (lv), (e),
+ State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- this->clear_state(mir_res, return_value);
- return_value = mv$(new_vs);
+ state_p = &return_value;
),
(Argument,
- auto& slot = args.at(e.idx);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &args.at(e);
),
(Local,
- auto& slot = locals.at(e);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &locals.at(e);
),
(Static,
- // Ignore.
- ),
- (Field,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
+ return ;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& cur_vs = *state_p;
+
+ // If this is not a composite, and it matches the new state
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
- // Not a composite, and no state change
+ // Early return
+ return;
}
- else
- {
- ::std::vector<State>* states_p;
+
+ state_p = nullptr;
+ TU_MATCHA( (w), (e),
+ (Field,
+ // Current isn't a composite, we need to change that
if( !cur_vs.is_composite() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w));
unsigned int n_fields = 0;
if( const auto* e = ty.m_data.opt_Tuple() )
{
n_fields = e->size();
}
+ // TODO: Fixed-size arrays
else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() )
{
const auto& e = ty.m_data.as_Path().binding.as_Struct();
@@ -573,94 +564,59 @@ namespace
)
)
}
- else {
+ else
+ {
MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty);
}
- auto new_cur_vs = this->allocate_composite(n_fields, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(n_fields, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- this->clear_state(mir_res, states[e.field_index]);
- states[e.field_index] = mv$(new_vs);
- }
- ),
- (Deref,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, e< states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
if( !cur_vs.is_composite() )
{
+ // TODO: Should this check if the type is Box?
//::HIR::TypeRef tmp;
//const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
- // TODO: Should this check if the type is Box?
- auto new_cur_vs = this->allocate_composite(2, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(2, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size");
- this->clear_state(mir_res, states[1]);
- states[1] = mv$(new_vs);
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
+ state_p = &states[1];
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, !cur_vs.is_composite(), "");
+ MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value");
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
+ MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value");
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
- // NOTE: Ignore
- ),
- (Downcast,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ // NOTE: Ignore
+ return ;
+ ),
+ (Downcast,
if( !cur_vs.is_composite() )
{
- auto new_cur_vs = this->allocate_composite(1, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
+ cur_vs = State(this->allocate_composite(1, cur_vs));
}
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
- }
-
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val));
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs));
this->clear_state(mir_res, states[0]);
states[0] = mv$(new_vs);
- }
+ )
)
- )
+ assert(state_p);
+ }
+ this->clear_state(mir_res, *state_p);
+ *state_p = mv$(new_vs);
}
};
@@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
(Incomplete,
),
(Return,
- state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({}));
+ state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return());
if( ENABLE_LEAK_DETECTOR )
{
auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) {
@@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
}
};
for(unsigned i = 0; i < state.locals.size(); i ++ ) {
- ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i));
+ ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i));
}
for(unsigned i = 0; i < state.args.size(); i ++ ) {
- ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i}));
+ ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i));
}
}
),
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index eae24031..6b8bcf79 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -33,7 +33,7 @@ struct MirMutator
::MIR::LValue new_temporary(::HIR::TypeRef ty)
{
- auto rv = ::MIR::LValue::make_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
+ auto rv = ::MIR::LValue::new_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
m_fcn.locals.push_back( mv$(ty) );
return rv;
}
@@ -75,8 +75,7 @@ namespace {
{
const auto& trait = *te.m_trait.m_trait_ptr;
- auto vtable_ty_spath = te.m_trait.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = resolve.m_crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
@@ -91,8 +90,11 @@ namespace {
}
}
-const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& path, ::HIR::TypeRef& out_ty)
+const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, const ::HIR::Path& path, ::HIR::TypeRef& out_ty)
{
+ const Span& sp = state.sp;
+ const auto& resolve = state.m_resolve;
+ TRACE_FUNCTION_F(path);
TU_MATCHA( (path.m_data), (pe),
(Generic,
const auto& constant = resolve.m_crate.get_constant_by_path(sp, pe.m_path);
@@ -155,6 +157,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
// Obtain `out_ty` by monomorphising the type in the trait.
auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr);
out_ty = monomorphise_type_with(sp, trait_cdef.m_type, monomorph_cb);
+ resolve.expand_associated_types(sp, out_ty);
if( best_impl )
{
ASSERT_BUG(sp, best_impl->m_constants.find(pe.item) != best_impl->m_constants.end(), "Item '" << pe.item << "' missing in impl for " << path);
@@ -164,13 +167,24 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
else
{
// No impl found at all, use the default in the trait
- return &trait_cdef.m_value_res;
+ if( trait_cdef.m_value_res.is_Defer() )
+ {
+ DEBUG(state << "Found deferred trait constant - " << path);
+ // Return null to force the replacement to not happen (yet)
+ // - Expansion and resolution of this constant happens after/in "Trans Monomorph"
+ return nullptr;
+ }
+ else
+ {
+ DEBUG("- Default " << trait_cdef.m_value_res);
+ return &trait_cdef.m_value_res;
+ }
}
}
),
(UfcsInherent,
const ::HIR::TypeImpl* best_impl = nullptr;
- // TODO: Associated constants (inherent)
+ // Associated constants (inherent)
resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; },
[&](const auto& impl) {
auto it = impl.m_constants.find(pe.item);
@@ -199,9 +213,9 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
if( path == ::HIR::GenericPath() )
- MIR_TODO(state, "Literal of type " << ty << " - " << path << " - " << lit);
- DEBUG("Unknown type " << ty << " - Return BorrowOf");
- return ::MIR::Constant( mv$(path) );
+ MIR_TODO(state, "Literal of type " << ty << " - " << lit);
+ DEBUG("Unknown type " << ty << ", but a path was provided - Return ItemAddr " << path);
+ return ::MIR::Constant::make_ItemAddr( box$(path) );
),
(Tuple,
MIR_ASSERT(state, lit.is_List(), "Non-list literal for Tuple - " << lit);
@@ -315,7 +329,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
}
else
{
- MIR_BUG(state, "Unexpected type - " << ty);
+ MIR_BUG(state, "Unexpected type for literal from " << path << " - " << ty << " (lit = " << lit << ")");
}
),
(Primitive,
@@ -328,6 +342,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
case ::HIR::CoreType::U32:
case ::HIR::CoreType::U16:
case ::HIR::CoreType::U8:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Uint({ lit.as_Integer(), te });
case ::HIR::CoreType::Isize:
case ::HIR::CoreType::I128:
@@ -335,11 +350,14 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
case ::HIR::CoreType::I32:
case ::HIR::CoreType::I16:
case ::HIR::CoreType::I8:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Int({ static_cast<int64_t>(lit.as_Integer()), te });
case ::HIR::CoreType::F64:
case ::HIR::CoreType::F32:
+ MIR_ASSERT(state, lit.is_Float(), "Literal for " << path << ": " << ty << " not a float, instead " << lit);
return ::MIR::Constant::make_Float({ lit.as_Float(), te });
case ::HIR::CoreType::Bool:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Bool({ !!lit.as_Integer() });
case ::HIR::CoreType::Str:
MIR_BUG(state, "Const of type `str` - " << path);
@@ -348,7 +366,6 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
),
(Pointer,
if( lit.is_BorrowPath() || lit.is_BorrowData() ) {
- // TODO:
MIR_TODO(state, "BorrowOf into pointer - " << lit << " into " << ty);
}
else {
@@ -360,7 +377,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
if( const auto* pp = lit.opt_BorrowPath() )
{
const auto& path = *pp;
- auto ptr_val = ::MIR::Constant::make_ItemAddr(path.clone());
+ auto ptr_val = ::MIR::Constant::make_ItemAddr(box$(path.clone()));
// TODO: Get the metadata type (for !Sized wrapper types)
if( te.inner->m_data.is_Slice() )
{
@@ -379,7 +396,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
auto vtable_path = ::HIR::Path(&ty == &tmp ? mv$(tmp) : ty.clone(), tep->m_trait.m_path.clone(), "vtable#");
- auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(mv$(vtable_path)) );
+ auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(box$(vtable_path)) );
return ::MIR::RValue::make_MakeDst({ ::MIR::Param(mv$(ptr_val)), mv$(vtable_val) });
}
@@ -436,6 +453,11 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
else {
MIR_TODO(state, "Const with type " << ty);
}
+ ),
+ (Function,
+ //MIR_TODO(state, "Const function pointer " << lit << " w/ type " << ty);
+ MIR_ASSERT(state, lit.is_BorrowPath(), "");
+ return ::MIR::Constant::make_ItemAddr( box$( lit.as_BorrowPath().clone() ) );
)
)
}
@@ -471,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
// Allocate a temporary for the vtable pointer itself
auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) );
// - Load the vtable and store it
- auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) });
+ auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() );
MIR_Cleanup_LValue(state, mutator, ptr_lv);
- auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) });
+ ptr_lv.m_wrappers.pop_back();
+ auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) });
mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
- auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
+ auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx );
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, fcn_lval);
@@ -504,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
),
(Tuple,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
),
(Named,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
)
@@ -653,8 +676,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
const auto& trait = *de.m_trait.m_trait_ptr;
// Obtain vtable type `::"path"::to::Trait#vtable`
- auto vtable_ty_spath = trait_path.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = state.m_crate.get_struct_by_path(state.sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone();
@@ -680,7 +702,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty);
::HIR::Path vtable { src_ty.clone(), trait_path.m_path.clone(), "vtable#" };
- out_meta_val = ::MIR::Constant::make_ItemAddr(mv$(vtable));
+ out_meta_val = ::MIR::Constant::make_ItemAddr(box$(vtable));
}
}
return true;
@@ -697,7 +719,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
bool source_is_dst = false;
if( MIR_Cleanup_Unsize_GetMetadata(state, mutator, dst_ty_inner, src_ty_inner, ptr_value, meta_value, meta_type, source_is_dst) )
{
- // TODO: There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer
+ // There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer
if( source_is_dst )
{
auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit());
@@ -756,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) );
ents.push_back( mv$(new_lval) );
@@ -772,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
),
@@ -785,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.new_temporary( mv$(ty_d) );
mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) );
@@ -802,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
)
@@ -827,7 +849,6 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
if( dte.type == ste.type )
{
- // TODO: Use unsize code above
return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value));
}
else
@@ -845,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval)
{
- TU_MATCHA( (lval), (le),
+ TU_MATCHA( (lval.m_root), (le),
(Return,
),
(Argument,
@@ -853,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
(Local,
),
(Static,
- ),
- (Field,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Deref,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Index,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- MIR_Cleanup_LValue(state, mutator, *le.idx);
- ),
- (Downcast,
- MIR_Cleanup_LValue(state, mutator, *le.val);
)
)
- // If this is a deref of Box, unpack and deref the inner pointer
- if( lval.is_Deref() )
+ for(size_t i = 0; i < lval.m_wrappers.size(); i ++)
{
- auto& le = lval.as_Deref();
+ if( !lval.m_wrappers[i].is_Deref() ) {
+ continue ;
+ }
+
+ // If this is a deref of Box, unpack and deref the inner pointer
::HIR::TypeRef tmp;
- const auto& ty = state.get_lvalue_type(tmp, *le.val);
+ const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i);
if( state.m_resolve.is_type_owned_box(ty) )
{
+ unsigned num_injected_fld_zeros = 0;
+
// Handle Box by extracting it to its pointer.
// - Locate (or remember) which field in Box is the pointer, and replace the inner by that field
// > Dumb idea, assume it's always the first field. Keep accessing until located.
@@ -904,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl);
typ = &tmp;
- auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 });
- le.val = box$(new_lval);
+ num_injected_fld_zeros ++;
}
MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ);
// We have reached the pointer. Good.
+
+ // Inject all of the field zero accesses (before the deref)
+ while(num_injected_fld_zeros--)
+ {
+ lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) );
+ }
}
}
}
@@ -938,6 +956,34 @@ void MIR_Cleanup_Param(const ::MIR::TypeResolve& state, MirMutator& mutator, ::M
MIR_Cleanup_Constant(state, mutator, e);
)
)
+
+ // Effectively a copy of the code that handles RValue::Constant below
+ if( p.is_Constant() && p.as_Constant().is_Const() )
+ {
+ const auto& ce = p.as_Constant().as_Const();
+ ::HIR::TypeRef c_ty;
+ const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, c_ty);
+ if( lit_ptr && !lit_ptr->is_Defer() )
+ {
+ DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr);
+ auto new_rval = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, c_ty.clone(), mv$(*ce.p));
+ if( auto* lv = new_rval.opt_Use() ) {
+ p = ::MIR::Param::make_LValue( ::std::move(*lv) );
+ }
+ else if( auto* c = new_rval.opt_Constant() ) {
+ MIR_Cleanup_Constant(state, mutator, *c);
+ p = ::MIR::Param::make_Constant( ::std::move(*c) );
+ }
+ else {
+ auto tmp_lv = mutator.in_temporary( mv$(c_ty), mv$(new_rval) );
+ p = ::MIR::Param::make_LValue( ::std::move(tmp_lv) );
+ }
+ }
+ else
+ {
+ DEBUG("No replacement for constant " << *ce.p);
+ }
+ }
}
void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
@@ -1010,9 +1056,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstMeta,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
// If the type is an array (due to a monomorpised generic?) then replace.
::HIR::TypeRef tmp;
@@ -1033,9 +1079,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstPtr,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
),
(MakeDst,
MIR_Cleanup_Param(state, mutator, re.ptr_val);
@@ -1066,22 +1112,22 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
auto& se = stmt.as_Assign();
TU_IFLET( ::MIR::RValue, se.src, Constant, e,
- // TODO: Replace `Const` with actual values
+ // Replace `Const` with actual values
TU_IFLET( ::MIR::Constant, e, Const, ce,
// 1. Find the constant
::HIR::TypeRef ty;
- const auto* lit_ptr = MIR_Cleanup_GetConstant(sp, resolve, ce.p, ty);
- if( lit_ptr )
+ const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, ty);
+ if( lit_ptr && !lit_ptr->is_Defer() )
{
- DEBUG("Replace constant " << ce.p << " with " << *lit_ptr);
- se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(ce.p));
+ DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr);
+ se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(*ce.p));
if( auto* p = se.src.opt_Constant() ) {
MIR_Cleanup_Constant(state, mutator, *p);
}
}
else
{
- DEBUG("No replacement for constant " << ce.p);
+ DEBUG("No replacement for constant " << *ce.p);
}
)
)
@@ -1198,13 +1244,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
e.args.reserve( fcn_ty.m_arg_types.size() );
for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++)
{
- e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) );
+ e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) );
}
// If the trait is Fn/FnMut, dereference the input value.
if( pe.trait.m_path == resolve.m_lang_FnOnce )
e.fcn = mv$(fcn_lvalue);
else
- e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) });
+ e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) );
}
}
)
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index 90b81d5d..d41bef7c 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -176,51 +176,18 @@ namespace {
#undef FMT
}
void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) {
- TU_MATCHA( (lval), (e),
- (Return,
- os << "RETURN";
- ),
- (Argument,
- os << "arg$" << e.idx;
- ),
- (Local,
- os << "_$" << e;
- ),
- (Static,
- os << e;
- ),
- (Field,
- os << "(";
- fmt_val(os, *e.val);
- os << ")." << e.field_index;
- ),
- (Deref,
- os << "*";
- fmt_val(os, *e.val);
- ),
- (Index,
- os << "(";
- fmt_val(os, *e.val);
- os << ")[";
- fmt_val(os, *e.idx);
- os << "]";
- ),
- (Downcast,
- fmt_val(os, *e.val);
- os << " as variant" << e.variant_index;
- )
- )
+ os << lval;
}
void fmt_val(::std::ostream& os, const ::MIR::Constant& e) {
TU_MATCHA( (e), (ce),
(Int,
- os << ce.v;
+ os << ce.v << "_" << ce.t;
),
(Uint,
- os << "0x" << ::std::hex << ce.v << ::std::dec;
+ os << "0x" << ::std::hex << ce.v << ::std::dec << "_" << ce.t;
),
(Float,
- os << ce.v;
+ os << ce.v << "_" << ce.t;
),
(Bool,
os << (ce.v ? "true" : "false");
@@ -244,10 +211,10 @@ namespace {
os << "\"" << ce << "\"";
),
(Const,
- os << ce.p;
+ os << *ce.p;
),
(ItemAddr,
- os << "addr " << ce;
+ os << "addr " << *ce;
)
)
}
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 5a629233..697f8141 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -18,6 +18,8 @@
#include "operations.hpp"
#include <mir/visit_crate_mir.hpp>
#include <hir/expr_state.hpp>
+#include <trans/target.hpp> // Target_GetSizeAndAlignOf - for `box`
+#include <cctype> // isdigit
namespace {
@@ -50,7 +52,7 @@ namespace {
struct LoopDesc {
ScopeHandle scope;
- ::std::string label;
+ RcString label;
unsigned int cur;
unsigned int next;
::MIR::LValue res_value;
@@ -161,6 +163,7 @@ namespace {
void destructure_from_ex(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, int allow_refutable=0) // 1 : yes, 2 : disallow binding
{
+ TRACE_FUNCTION_F(pat << ", allow_refutable=" << allow_refutable);
if( allow_refutable != 3 && pat.m_binding.is_valid() ) {
if( allow_refutable == 2 ) {
BUG(sp, "Binding when not expected");
@@ -173,6 +176,11 @@ namespace {
destructure_from_ex(sp, pat, lval.clone(), 3);
}
+ for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++)
+ {
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
+ }
+
switch( pat.m_binding.m_type )
{
case ::HIR::PatternBinding::Type::Move:
@@ -206,90 +214,117 @@ namespace {
allow_refutable = 2;
}
- TU_MATCHA( (pat.m_data), (e),
- (Any,
- ),
- (Box,
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
- ),
- (Ref,
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
- ),
- (Tuple,
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
+ }
+
+ TU_MATCH_HDRA( (pat.m_data), {)
+ TU_ARMA(Any, e) {
+ }
+ TU_ARMA(Box, e) {
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
+ }
+ TU_ARMA(Ref, e) {
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
+ }
+ TU_ARMA(Tuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
- ),
- (SplitTuple,
+ }
+ TU_ARMA(SplitTuple, e) {
assert(e.total_size >= e.leading.size() + e.trailing.size());
for(unsigned int i = 0; i < e.leading.size(); i ++ )
{
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
// TODO: Is there a binding in the middle?
unsigned int ofs = e.total_size - e.trailing.size();
for(unsigned int i = 0; i < e.trailing.size(); i ++ )
{
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable);
}
- ),
- (StructValue,
+ }
+ TU_ARMA(StructValue, e) {
// Nothing.
- ),
- (StructTuple,
+ }
+ TU_ARMA(StructTuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
const auto& str = *e.binding;
- const auto& fields = str.m_data.as_Named();
- for(const auto& fld_pat : e.sub_patterns)
+ if( !e.sub_patterns.empty() )
{
- unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable);
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << pat);
+ const auto& fields = str.m_data.as_Named();
+ for(const auto& fld_pat : e.sub_patterns)
+ {
+ unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable);
+ }
+ }
}
- ),
// Refutable
- (Value,
+ TU_ARMA(Value, e) {
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
- ),
- (Range,
+ }
+ TU_ARMA(Range, e) {
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
- ),
- (EnumValue,
+ }
+ TU_ARMA(EnumValue, e) {
const auto& enm = *e.binding_ptr;
if( enm.num_variants() > 1 )
{
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
}
- ),
- (EnumTuple,
+ }
+ TU_ARMA(EnumTuple, e) {
const auto& enm = *e.binding_ptr;
- ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat);
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ const auto& variants = enm.m_data.as_Data();
+ // TODO: Check that this is the only non-impossible arm
+ if( !allow_refutable )
+ {
+ for(size_t i = 0; i < variants.size(); i ++)
+ {
+ const auto& var_ty = variants[i].type;
+ if( i == e.binding_idx ) {
+ continue;
+ }
+ ::HIR::TypeRef tmp;
+ const auto& ty = (monomorphise_type_needed(var_ty) ? tmp = monomorphise_type_with(sp, var_ty, monomorphise_type_get_cb(sp, nullptr, &e.path.m_params, nullptr)) : var_ty);
+ if( m_builder.resolve().type_is_impossible(sp, ty) ) {
+ continue;
+ }
+ ERROR(sp, E0000, "Variant " << variants[i].name << " not handled");
+ }
+ }
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable);
}
- ),
- (EnumStruct,
+ }
+ TU_ARMA(EnumStruct, e) {
const auto& enm = *e.binding_ptr;
ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat);
ASSERT_BUG(sp, enm.m_data.is_Data(), "Expected struct variant - " << pat);
const auto& var = enm.m_data.as_Data()[e.binding_idx];;
const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path);
const auto& fields = str.m_data.as_Named();
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(const auto& fld_pat : e.sub_patterns)
{
unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable);
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable);
}
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, e) {
// These are only refutable if T is [T]
bool ty_is_array = false;
m_builder.with_val_type(sp, lval, [&ty_is_array](const auto& ty){
@@ -301,7 +336,7 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
else
@@ -312,11 +347,11 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
- ),
- (SplitSlice,
+ }
+ TU_ARMA(SplitSlice, e) {
// These are only refutable if T is [T]
bool ty_is_array = false;
unsigned int array_size = 0;
@@ -340,7 +375,7 @@ namespace {
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = 0 + i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -349,7 +384,7 @@ namespace {
for(unsigned int i = 0; i < e.trailing.size(); i ++)
{
unsigned int idx = array_size - e.trailing.size() + i;
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
}
else
@@ -375,13 +410,13 @@ namespace {
::MIR::LValue len_lval;
if( e.extra_bind.is_valid() || e.trailing.size() > 0 )
{
- len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() }));
+ len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) }));
}
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -392,9 +427,10 @@ namespace {
// 2. Obtain pointer to element
::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind);
::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp,
- ::HIR::TypeRef::new_pointer( bt, inner_type.clone() ),
- ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast<unsigned int>(e.leading.size()) }) })
+ ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ),
+ ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast<unsigned int>(e.leading.size()) ) })
);
+ // TODO: Cast to raw pointer? Or keep as a borrow?
// Construct fat pointer
m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) );
@@ -407,15 +443,20 @@ namespace {
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize }));
::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// Recurse with the indexed value
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable);
}
}
}
- )
- )
+ }
+ } // TU_MATCH_HDRA
}
// -- ExprVisitor
+ void visit_node_ptr(::HIR::ExprNodeP& node_p) override
+ {
+ DEBUG(node_p.get());
+ ::HIR::ExprVisitor::visit_node_ptr(node_p);
+ }
void visit(::HIR::ExprNode_Block& node) override
{
TRACE_FUNCTION_F("_Block");
@@ -521,7 +562,7 @@ namespace {
// Outputs can also (sometimes) be rvalues (only for `*m`?)
for(auto& v : node.m_outputs) {
this->visit_node_ptr(v.value);
- if( v.spec[0] != '=' )
+ if( v.spec[0] != '=' && v.spec[0] != '+' ) // TODO: what does '+' mean?
ERROR(node.span(), E0000, "Assembly output specifiers must start with =");
::MIR::LValue lv;
if(v.spec[1] == '*')
@@ -539,7 +580,7 @@ namespace {
TRACE_FUNCTION_F("_Return");
this->visit_node_ptr(node.m_value);
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) );
m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() );
m_builder.end_block( ::MIR::Terminator::make_Return({}) );
}
@@ -643,6 +684,11 @@ namespace {
}
target_block = &*it;
}
+ else {
+ if( target_block->label != "" && target_block->label.c_str()[0] == '#' ) {
+ TODO(node.span(), "Break within try block, want to break parent loop instead");
+ }
+ }
if( node.m_continue ) {
ASSERT_BUG(node.span(), !node.m_value, "Continue with a value isn't valid");
@@ -1217,7 +1263,7 @@ namespace {
}
void visit(::HIR::ExprNode_Cast& node) override
{
- TRACE_FUNCTION_F("_Cast");
+ TRACE_FUNCTION_F("_Cast " << node.m_res_type);
this->visit_node_ptr(node.m_value);
const auto& ty_out = node.m_res_type;
@@ -1231,11 +1277,15 @@ namespace {
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type);
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_out.m_data), (de),
- (
+ TU_MATCH_HDRA( (ty_out.m_data), {)
+ default:
BUG(node.span(), "Invalid cast to " << ty_out << " from " << ty_in);
- ),
- (Pointer,
+ TU_ARMA(Function, de) {
+ // Just trust the previous stages.
+ ASSERT_BUG(node.span(), ty_in.m_data.is_Function(), ty_in);
+ ASSERT_BUG(node.span(), de.m_arg_types == ty_in.m_data.as_Function().m_arg_types, ty_in);
+ }
+ TU_ARMA(Pointer, de) {
if( ty_in.m_data.is_Primitive() ) {
const auto& ie = ty_in.m_data.as_Primitive();
switch(ie)
@@ -1269,8 +1319,8 @@ namespace {
else {
BUG(node.span(), "Cannot cast to pointer from " << ty_in);
}
- ),
- (Primitive,
+ }
+ TU_ARMA(Primitive, de) {
switch(de)
{
case ::HIR::CoreType::Str:
@@ -1337,8 +1387,8 @@ namespace {
}
break;
}
- )
- )
+ }
+ }
auto res = m_builder.new_temporary(node.m_res_type);
m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue::make_Cast({ mv$(val), node.m_res_type.clone() }));
m_builder.set_result( node.span(), mv$(res) );
@@ -1435,7 +1485,7 @@ namespace {
limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize });
),
(Slice,
- limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() });
+ limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) });
)
)
@@ -1469,7 +1519,13 @@ namespace {
m_builder.set_cur_block( arm_continue );
}
- m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) );
+ if( !index.is_Local())
+ {
+ auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize);
+ m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index));
+ index = mv$(local_idx);
+ }
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) );
}
void visit(::HIR::ExprNode_Deref& node) override
@@ -1481,8 +1537,8 @@ namespace {
this->visit_node_ptr(node.m_value);
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val);
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_val.m_data), (te),
- (
+ TU_MATCH_HDRA( (ty_val.m_data), {)
+ default: {
if( m_builder.is_type_owned_box( ty_val ) )
{
// Box magically derefs.
@@ -1543,20 +1599,31 @@ namespace {
m_builder.set_cur_block(ok_block);
}
- ),
- (Pointer,
+ }
+ TU_ARMA(Pointer, te) {
// Deref on a pointer - TODO: Requires unsafe
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, te) {
// Deref on a borrow - Always valid... assuming borrowck is there :)
- )
- )
+ }
+ }
- m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) );
}
void visit(::HIR::ExprNode_Emplace& node) override
{
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19:
+ return visit_emplace_119(node);
+ case TargetVersion::Rustc1_29:
+ return visit_emplace_129(node);
+ }
+ throw "BUG: Unhandled target version";
+ }
+ void visit_emplace_119(::HIR::ExprNode_Emplace& node)
+ {
if( node.m_type == ::HIR::ExprNode_Emplace::Type::Noop ) {
return node.m_value->visit(*this);
}
@@ -1652,7 +1719,7 @@ namespace {
// 3. Get the value and assign it into `place_raw`
node.m_value->visit(*this);
auto val = m_builder.get_result(node.span());
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false );
// 3. Return a call to `finalize`
::HIR::Path finalize_path(::HIR::GenericPath {});
@@ -1689,6 +1756,92 @@ namespace {
m_builder.mark_value_assigned(node.span(), res);
m_builder.set_result( node.span(), mv$(res) );
}
+ void visit_emplace_129(::HIR::ExprNode_Emplace& node)
+ {
+ assert( node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer );
+ const auto& data_ty = node.m_value->m_res_type;
+
+ node.m_value->visit(*this);
+ auto val = m_builder.get_result(node.span());
+
+ const auto& lang_exchange_malloc = m_builder.crate().get_lang_item_path(node.span(), "exchange_malloc");
+ const auto& lang_owned_box = m_builder.crate().get_lang_item_path(node.span(), "owned_box");
+
+ ::HIR::PathParams trait_params_data;
+ trait_params_data.m_types.push_back( data_ty.clone() );
+
+ // 1. Determine the size/alignment of the type
+ ::MIR::Param size_param, align_param;
+ size_t item_size, item_align;
+ if( Target_GetSizeAndAlignOf(node.span(), m_builder.resolve(), data_ty, item_size, item_align) ) {
+ size_param = ::MIR::Constant::make_Int({ static_cast<int64_t>(item_size), ::HIR::CoreType::Usize });
+ align_param = ::MIR::Constant::make_Int({ static_cast<int64_t>(item_align), ::HIR::CoreType::Usize });
+ }
+ else {
+ // Insert calls to "size_of" and "align_of" intrinsics
+ auto size_slot = m_builder.new_temporary( ::HIR::CoreType::Usize );
+ auto size__panic = m_builder.new_bb_unlinked();
+ auto size__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ size__ok, size__panic,
+ size_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "size_of", trait_params_data.clone() }),
+ {}
+ }));
+ m_builder.set_cur_block(size__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(size__ok);
+ auto align_slot = m_builder.new_temporary( ::HIR::CoreType::Usize );
+ auto align__panic = m_builder.new_bb_unlinked();
+ auto align__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ align__ok, align__panic,
+ align_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "align_of", trait_params_data.clone() }),
+ {}
+ }));
+ m_builder.set_cur_block(align__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(align__ok);
+
+ size_param = ::std::move(size_slot);
+ align_param = ::std::move(align_slot);
+ }
+
+ // 2. Call the allocator function and get a pointer
+ // - NOTE: "exchange_malloc" returns a `*mut u8`, need to cast that to the target type
+ auto place_raw_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, ::HIR::CoreType::U8);
+ auto place_raw = m_builder.new_temporary( place_raw_type );
+
+ auto place__panic = m_builder.new_bb_unlinked();
+ auto place__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ place__ok, place__panic,
+ place_raw.clone(), ::HIR::Path(lang_exchange_malloc),
+ make_vec2<::MIR::Param>( ::std::move(size_param), ::std::move(align_param) )
+ }));
+ m_builder.set_cur_block(place__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(place__ok);
+
+ auto place_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, data_ty.clone());
+ auto place = m_builder.new_temporary( place_type );
+ m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() }));
+ // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment)
+ m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false);
+ // 4. Convert the pointer into an `owned_box`
+ auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box));
+ auto res = m_builder.new_temporary(res_type);
+ auto cast__panic = m_builder.new_bb_unlinked();
+ auto cast__ok = m_builder.new_bb_unlinked();
+ ::HIR::PathParams transmute_params;
+ transmute_params.m_types.push_back( res_type.clone() );
+ transmute_params.m_types.push_back( place_type.clone() );
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ cast__ok, cast__panic,
+ res.clone(), ::MIR::CallTarget::make_Intrinsic({ "transmute", mv$(transmute_params) }),
+ make_vec1( ::MIR::Param( mv$(place) ) )
+ }));
+ m_builder.set_cur_block(cast__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(cast__ok);
+
+ m_builder.set_result(node.span(), mv$(res));
+ }
void visit(::HIR::ExprNode_TupleVariant& node) override
{
@@ -1810,6 +1963,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({ RcString(FMT("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") )
@@ -1901,29 +2062,29 @@ namespace {
}
void visit(::HIR::ExprNode_Field& node) override
{
- TRACE_FUNCTION_F("_Field");
+ TRACE_FUNCTION_F("_Field \"" << node.m_field << "\"");
this->visit_node_ptr(node.m_value);
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type);
const auto& val_ty = node.m_value->m_res_type;
unsigned int idx;
- if( '0' <= node.m_field[0] && node.m_field[0] <= '9' ) {
- ::std::stringstream(node.m_field) >> idx;
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ if( ::std::isdigit(node.m_field.c_str()[0]) ) {
+ ::std::stringstream(node.m_field.c_str()) >> idx;
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) {
const auto& str = **bep;
const auto& fields = str.m_data.as_Named();
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) {
const auto& unm = **bep;
const auto& fields = unm.m_variants;
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) );
}
else {
BUG(node.span(), "Field access on non-union/struct - " << val_ty);
@@ -2041,7 +2202,7 @@ namespace {
// TODO: Ideally, the creation of the wrapper function would happen somewhere before trans?
auto tmp = m_builder.new_temporary( node.m_res_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
return ;
}
@@ -2052,11 +2213,11 @@ namespace {
),
(Constant,
auto tmp = m_builder.new_temporary( e.m_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
m_builder.set_result( node.span(), mv$(tmp) );
),
(Static,
- m_builder.set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) );
),
(StructConstant,
// TODO: Why is this still a PathValue?
@@ -2101,13 +2262,13 @@ namespace {
fcn_ty_data.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) );
}
auto tmp = m_builder.new_temporary( ::HIR::TypeRef( mv$(fcn_ty_data) ) );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
),
(StructConstructor,
// TODO: Ideally, the creation of the wrapper function would happen somewhere before this?
auto tmp = m_builder.new_temporary( node.m_res_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
)
)
@@ -2119,13 +2280,13 @@ namespace {
ASSERT_BUG(sp, it != tr.m_values.end(), "Cannot find trait item for " << node.m_path);
TU_MATCHA( (it->second), (e),
(Constant,
- m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
),
(Static,
TODO(sp, "Associated statics (non-rustc) - " << node.m_path);
),
(Function,
- m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
)
)
),
@@ -2141,7 +2302,7 @@ namespace {
{
auto it = impl.m_methods.find(pe.item);
if( it != impl.m_methods.end() ) {
- m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
return true;
}
}
@@ -2149,7 +2310,7 @@ namespace {
{
auto it = impl.m_constants.find(pe.item);
if( it != impl.m_constants.end() ) {
- m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
return true;
}
}
@@ -2175,7 +2336,7 @@ namespace {
ASSERT_BUG(sp, str.m_data.is_Named(), "");
const ::HIR::t_struct_fields& fields = str.m_data.as_Named();
- ::MIR::LValue base_val;
+ auto base_val = ::MIR::LValue::new_Return();
if( node.m_base_value )
{
DEBUG("_StructLiteral - base");
@@ -2216,7 +2377,7 @@ namespace {
if( !node.m_base_value) {
ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified");
}
- values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i });
+ values[i] = ::MIR::LValue::new_Field( base_val.clone(), i );
}
else {
// Partial move support will handle dropping the rest?
@@ -2233,13 +2394,18 @@ namespace {
{
TRACE_FUNCTION_F("_StructLiteral");
- TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e),
- (Unbound, ),
- (Opaque, ),
- (Enum,
- auto enum_path = node.m_path.clone();
+ ASSERT_BUG(node.span(), node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path);
+ const auto& ty_path = node.m_path.m_data.as_Generic();
+
+ TU_MATCH_HDRA( (node.m_res_type.m_data.as_Path().binding), {)
+ TU_ARMA(Unbound, _e) {
+ }
+ TU_ARMA(Opaque, _e) {
+ }
+ TU_ARMA(Enum, e) {
+ auto enum_path = ty_path.clone();
enum_path.m_path.m_components.pop_back();
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
size_t idx = enm.find_variant(var_name);
@@ -2249,7 +2415,7 @@ namespace {
const auto& str = *var_ty.m_data.as_Path().binding.as_Struct();
// Take advantage of the identical generics to cheaply clone/monomorph the path.
- ::HIR::GenericPath struct_path = node.m_path.clone();
+ ::HIR::GenericPath struct_path = ty_path.clone();
struct_path.m_path = var_ty.m_data.as_Path().path.m_data.as_Generic().m_path;
this->visit_sl_inner(node, str, struct_path);
@@ -2264,22 +2430,25 @@ namespace {
static_cast<unsigned>(idx),
mv$(v)
}) );
- ),
- (Union,
+ }
+ TU_ARMA(Union, e) {
BUG(node.span(), "_StructLiteral Union isn't valid?");
- ),
- (Struct,
+ }
+ TU_ARMA(ExternType, e) {
+ BUG(node.span(), "_StructLiteral ExternType isn't valid?");
+ }
+ TU_ARMA(Struct, e) {
if(e->m_data.is_Unit()) {
m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({
- node.m_path.clone(),
+ ty_path.clone(),
{}
}) );
return ;
}
- this->visit_sl_inner(node, *e, node.m_path);
- )
- )
+ this->visit_sl_inner(node, *e, ty_path);
+ }
+ }
}
void visit(::HIR::ExprNode_UnionLiteral& node) override
{
@@ -2391,7 +2560,7 @@ namespace {
else
{
ev.define_vars_from(ptr->span(), arg.first);
- ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i}));
+ ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i));
}
i ++;
}
@@ -2402,8 +2571,9 @@ namespace {
}
// NOTE: Can't clean up yet, as consteval isn't done
- //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type);
- MIR_Validate(resolve, path, fcn, args, ptr->m_res_type);
+ //MIR_Cleanup(resolve, path, fcn, args, ret_ty);
+ //DEBUG("MIR Dump:" << ::std::endl << FMT_CB(ss, MIR_Dump_Fcn(ss, fcn, 1);));
+ MIR_Validate(resolve, path, fcn, args, ret_ty);
if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) {
MIR_Validate_Full(resolve, path, fcn, args, ptr->m_res_type);
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 0dcbd65b..c29d6283 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -70,8 +70,8 @@ TAGGED_UNION_EX(VarState, (), Invalid, (
(), (),
(
VarState clone() const;
- bool operator==(VarState& x) const;
- bool operator!=(VarState& x) const { return !(*this == x); }
+ bool operator==(const VarState& x) const;
+ bool operator!=(const VarState& x) const { return !(*this == x); }
)
);
extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x);
@@ -110,7 +110,7 @@ TAGGED_UNION(ScopeType, Owning,
}),
// State which should end up with no mutation of variable states
(Freeze, struct {
- //::std::map<unsigned int,VarState> changed_slots;
+ ::std::map<unsigned int,VarState> changed_slots;
//::std::map<unsigned int,VarState> changed_args;
})
);
@@ -188,13 +188,10 @@ public:
// - Values
::MIR::LValue get_variable(const Span& sp, unsigned idx) const {
- // DIASBLED: State tracking doesn't support arguments in loops/splits
-#if 1
auto it = m_var_arg_mappings.find(idx);
if(it != m_var_arg_mappings.end())
- return ::MIR::LValue::make_Argument({ it->second });
-#endif
- return ::MIR::LValue::make_Local( idx );
+ return ::MIR::LValue::new_Argument(it->second);
+ return ::MIR::LValue::new_Local(idx);
}
::MIR::LValue new_temporary(const ::HIR::TypeRef& ty);
::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val);
@@ -224,7 +221,7 @@ public:
// - Statements
// Push an assignment. NOTE: This also marks the rvalue as moved
- void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val);
+ void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true);
// Push a drop (likely only used by scope cleanup)
void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u);
// Push a shallow drop (for Box)
@@ -296,8 +293,7 @@ private:
const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const;
VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type);
- const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0);
- VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv);
+ VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv, bool expect_valid=false);
void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop);
@@ -306,11 +302,11 @@ private:
void complete_scope(ScopeDef& sd);
public:
- void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const;
+ void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const;
bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const;
// Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer
- const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
+ ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
};
class MirConverter:
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index b8fabdc0..536842b7 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -395,6 +395,8 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
else
{
ac.has_condition = false;
+ ac.cond_start = ~0u;
+ ac.cond_false = ~0u;
}
// Code
@@ -802,6 +804,9 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal
)
)
),
+ (ExternType,
+ TODO(sp, "Match extern type");
+ ),
(Union,
TODO(sp, "Match union");
),
@@ -886,9 +891,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal
)
)
}
-void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty)
+void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& top_ty)
{
- TRACE_FUNCTION_F("pat="<<pat<<", ty="<<ty<<", m_field_path=[" << m_field_path << "]");
+ static ::HIR::Pattern empty_pattern;
+ TRACE_FUNCTION_F("pat="<<pat<<", ty="<<top_ty<<", m_field_path=[" << m_field_path << "]");
struct H {
static uint64_t get_pattern_value_int(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::Pattern::Value& val) {
TU_MATCH_DEF( ::HIR::Pattern::Value, (val), (e),
@@ -922,6 +928,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
}
};
+ const auto* ty_p = &top_ty;
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ if( !ty_p->m_data.is_Borrow() )
+ BUG(sp, "Deref step " << i << "/" << pat.m_implicit_deref_count << " hit a non-borrow " << *ty_p << " from " << top_ty);
+ ty_p = &*ty_p->m_data.as_Borrow().inner;
+ m_field_path.push_back( FIELD_DEREF );
+ }
+ const auto& ty = *ty_p;
+
// TODO: Outer handling for Value::Named patterns
// - Convert them into either a pattern, or just a variant of this function that operates on ::HIR::Literal
// > It does need a way of handling unknown-value constants (e.g. <GenericT as Foo>::CONST)
@@ -931,6 +947,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
if( pve.binding )
{
this->append_from_lit(sp, pve.binding->m_value_res, ty);
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ m_field_path.pop_back();
+ }
return ;
}
else
@@ -940,20 +960,23 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
- TU_MATCHA( (ty.m_data), (e),
- (Infer, BUG(sp, "Ivar for in match type"); ),
- (Diverge,
+ TU_MATCH_HDR( (ty.m_data), {)
+ TU_ARM(ty.m_data, Infer, e) {
+ BUG(sp, "Ivar for in match type");
+ }
+ TU_ARM(ty.m_data, Diverge, e) {
// Since ! can never exist, mark this arm as impossible.
// TODO: Marking as impossible (and not emitting) leads to exhuaustiveness failure.
//this->m_is_impossible = true;
- ),
- (Primitive,
- TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
- ( BUG(sp, "Matching primitive with invalid pattern - " << pat); ),
- (Any,
+ }
+ TU_ARM(ty.m_data, Primitive, e) {
+ TU_MATCH_HDR( (pat.m_data), {)
+ default:
+ BUG(sp, "Matching primitive with invalid pattern - " << pat);
+ TU_ARM(pat.m_data, Any, pe) {
this->push_rule( PatternRule::make_Any({}) );
- ),
- (Range,
+ }
+ TU_ARM(pat.m_data, Range, pe) {
switch(e)
{
case ::HIR::CoreType::F32:
@@ -994,8 +1017,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
BUG(sp, "Hit match over `str` - must be `&str`");
break;
}
- ),
- (Value,
+ }
+ TU_ARM(pat.m_data, Value, pe) {
switch(e)
{
case ::HIR::CoreType::F32:
@@ -1035,16 +1058,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
BUG(sp, "Hit match over `str` - must be `&str`");
break;
}
- )
- )
- ),
- (Tuple,
+ }
+ }
+ }
+ TU_ARM(ty.m_data, Tuple, e) {
m_field_path.push_back(0);
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching tuple with invalid pattern - " << pat); ),
(Any,
for(const auto& sty : e) {
- this->append_from(sp, pat, sty);
+ this->append_from(sp, empty_pattern, sty);
m_field_path.back() ++;
}
),
@@ -1070,22 +1093,22 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
m_field_path.pop_back();
- ),
- (Path,
+ }
+ TU_ARM(ty.m_data, Path, e) {
// This is either a struct destructure or an enum
- TU_MATCHA( (e.binding), (pbe),
- (Unbound,
+ TU_MATCH_HDRA( (e.binding), {)
+ TU_ARMA(Unbound, pbe) {
BUG(sp, "Encounterd unbound path - " << e.path);
- ),
- (Opaque,
+ }
+ TU_ARMA(Opaque, be) {
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching opaque type with invalid pattern - " << pat); ),
(Any,
this->push_rule( PatternRule::make_Any({}) );
)
)
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pbe) {
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty);
this->m_resolve.expand_associated_types(sp, rv);
@@ -1101,7 +1124,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
(Any,
// _ on a box, recurse into the box type.
m_field_path.push_back(FIELD_DEREF);
- this->append_from(sp, pat, inner_ty);
+ this->append_from(sp, empty_pattern, inner_ty);
m_field_path.pop_back();
),
(Box,
@@ -1132,12 +1155,12 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Match not allowed, " << ty << " with " << pat); ),
(Any,
- // - Recurse into type and use the same pattern again
+ // - Recurse into type using an empty pattern
for(const auto& fld : sd)
{
::HIR::TypeRef tmp;
const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent);
- this->append_from(sp, pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
m_field_path.back() ++;
}
),
@@ -1166,7 +1189,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
{
::HIR::TypeRef tmp;
const auto& sty_mono = (monomorphise_type_needed(fld.second.ent) ? tmp = monomorph(fld.second.ent) : fld.second.ent);
- this->append_from(sp, pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
m_field_path.back() ++;
}
m_field_path.pop_back();
@@ -1182,8 +1205,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
auto it = ::std::find_if( pe.sub_patterns.begin(), pe.sub_patterns.end(), [&](const auto& x){ return x.first == fld.first; } );
if( it == pe.sub_patterns.end() )
{
- ::HIR::Pattern any_pat {};
- this->append_from(sp, any_pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
}
else
{
@@ -1196,11 +1218,24 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
)
- ),
- (Union,
- TODO(sp, "Match over union - " << ty);
- ),
- (Enum,
+ }
+ TU_ARMA(Union, pbe) {
+ TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
+ ( TODO(sp, "Match over union - " << ty << " with " << pat); ),
+ (Any,
+ this->push_rule( PatternRule::make_Any({}) );
+ )
+ )
+ }
+ TU_ARMA(ExternType, pbe) {
+ TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
+ ( BUG(sp, "Matching extern type with invalid pattern - " << pat); ),
+ (Any,
+ this->push_rule( PatternRule::make_Any({}) );
+ )
+ )
+ }
+ TU_ARMA(Enum, pbe) {
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty);
this->m_resolve.expand_associated_types(sp, rv);
@@ -1287,10 +1322,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
this->push_rule( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) );
)
)
- )
- )
- ),
- (Generic,
+ }
+ }
+ }
+ TU_ARM(ty.m_data, Generic, e) {
// Generics don't destructure, so the only valid pattern is `_`
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Match not allowed, " << ty << " with " << pat); ),
@@ -1298,29 +1333,29 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
this->push_rule( PatternRule::make_Any({}) );
)
)
- ),
- (TraitObject,
+ }
+ TU_ARM(ty.m_data, TraitObject, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a trait object");
}
- ),
- (ErasedType,
+ }
+ TU_ARM(ty.m_data, ErasedType, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over an erased type");
}
- ),
- (Array,
+ }
+ TU_ARM(ty.m_data, Array, e) {
// Sequential match just like tuples.
m_field_path.push_back(0);
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching array with invalid pattern - " << pat); ),
(Any,
for(unsigned int i = 0; i < e.size_val; i ++) {
- this->append_from(sp, pat, *e.inner);
+ this->append_from(sp, empty_pattern, *e.inner);
m_field_path.back() ++;
}
),
@@ -1336,8 +1371,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
m_field_path.pop_back();
- ),
- (Slice,
+ }
+ TU_ARM(ty.m_data, Slice, e) {
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
(
BUG(sp, "Matching over [T] with invalid pattern - " << pat);
@@ -1393,18 +1428,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
}) );
)
)
- ),
- (Borrow,
+ }
+ TU_ARM(ty.m_data, Borrow, e) {
m_field_path.push_back( FIELD_DEREF );
- TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
- ( BUG(sp, "Matching borrow invalid pattern - " << pat); ),
- (Any,
- this->append_from( sp, pat, *e.inner );
- ),
- (Ref,
+ TU_MATCH_HDR( (pat.m_data), {)
+ default:
+ BUG(sp, "Matching borrow invalid pattern - " << ty << " with " << pat);
+ TU_ARM(pat.m_data, Any, pe) {
+ this->append_from( sp, empty_pattern, *e.inner );
+ }
+ TU_ARM(pat.m_data, Ref, pe) {
this->append_from( sp, *pe.sub, *e.inner );
- ),
- (Value,
+ }
+ TU_ARM(pat.m_data, Value, pe) {
// TODO: Check type?
if( pe.val.is_String() ) {
const auto& s = pe.val.as_String();
@@ -1423,32 +1459,36 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
else {
BUG(sp, "Matching borrow invalid pattern - " << pat);
}
- )
- )
+ }
+ }
m_field_path.pop_back();
- ),
- (Pointer,
+ }
+ TU_ARM(ty.m_data, Pointer, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a pointer");
}
- ),
- (Function,
+ }
+ TU_ARM(ty.m_data, Function, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a functon pointer");
}
- ),
- (Closure,
+ }
+ TU_ARM(ty.m_data, Closure, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a closure");
}
- )
- )
+ }
+ }
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ m_field_path.pop_back();
+ }
}
namespace {
@@ -1456,7 +1496,7 @@ namespace {
Ordering ord_rule_compatible(const PatternRule& a, const PatternRule& b)
{
if(a.tag() != b.tag())
- return ::ord( (unsigned)a.tag(), b.tag() );
+ return ::ord( (unsigned)a.tag(), (unsigned)b.tag() );
TU_MATCHA( (a, b), (ae, be),
(Any,
@@ -1699,13 +1739,13 @@ namespace {
),
(Tuple,
ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range");
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
cur_ty = &e[idx];
),
(Path,
if( idx == FIELD_DEREF ) {
// TODO: Check that the path is Box
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref( mv$(lval) );
cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0);
break;
}
@@ -1716,6 +1756,9 @@ namespace {
(Opaque,
BUG(sp, "Destructuring an opaque type - " << *cur_ty);
),
+ (ExternType,
+ BUG(sp, "Destructuring an extern type - " << *cur_ty);
+ ),
(Struct,
// TODO: Should this do a call to expand_associated_types?
auto monomorph = [&](const auto& ty) {
@@ -1737,7 +1780,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
),
(Named,
assert( idx < fields.size() );
@@ -1749,7 +1792,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
)
)
),
@@ -1768,7 +1811,7 @@ namespace {
else {
cur_ty = &fld.second.ent;
}
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
),
(Enum,
auto monomorph_to_ptr = [&](const auto& ty)->const auto* {
@@ -1788,7 +1831,7 @@ namespace {
const auto& var = variants[idx];
cur_ty = monomorph_to_ptr(var.type);
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
)
)
),
@@ -1805,7 +1848,7 @@ namespace {
assert(idx < e.size_val);
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
@@ -1815,16 +1858,16 @@ namespace {
(Slice,
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
// 1. Create an LValue containing the size of this slice subtract `idx`
- auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() }));
+ auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) }));
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize }));
auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// 2. Return _Index with that value
- lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) });
+ lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local());
}
),
(Borrow,
@@ -1838,7 +1881,7 @@ namespace {
cur_ty = &*e.inner;
}
DEBUG(i << " " << *cur_ty);
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
),
(Pointer,
ERROR(sp, E0000, "Attempting to match over a pointer");
@@ -1942,14 +1985,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
DEBUG("ty = " << ity << ", val = " << val);
const auto& ty = ity;
- TU_MATCHA( (ty.m_data), (te),
- (Infer,
+ TU_MATCH_HDRA( (ty.m_data), {)
+ TU_ARMA(Infer, _te) {
BUG(sp, "Hit _ in type - " << ty);
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, _te) {
BUG(sp, "Matching over !");
- ),
- (Primitive,
+ }
+ TU_ARMA(Primitive, te) {
switch(te)
{
case ::HIR::CoreType::Bool: {
@@ -2116,17 +2159,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
case ::HIR::CoreType::Str: {
ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), "");
const auto& v = rule.as_Value();
+ ASSERT_BUG(sp, val.is_Deref(), "");
+ val.m_wrappers.pop_back();
+ auto str_val = mv$(val);
auto succ_bb = builder.new_bb_unlinked();
auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() ));
- auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) }));
+ auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) );
builder.set_cur_block(succ_bb);
} break;
}
- ),
- (Path,
+ }
+ TU_ARMA(Path, te) {
TU_MATCHA( (te.binding), (pbe),
(Unbound,
BUG(sp, "Encounterd unbound path - " << te.path);
@@ -2151,6 +2197,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
(Union,
TODO(sp, "Match over Union");
),
+ (ExternType,
+ TODO(sp, "Match over ExternType");
+ ),
(Enum,
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, te.path.m_data.as_Generic().m_params, ty);
@@ -2182,26 +2231,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Recurse with the new ruleset
MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp,
re.sub_rules.data(), re.sub_rules.size(),
- var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1,
+ var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1,
fail_bb
);
}
) // TypePathBinding::Enum
)
- ), // Type::Data::Path
- (Generic,
+ } // Type::Data::Path
+ TU_ARMA(Generic, _te) {
BUG(sp, "Attempting to match a generic");
- ),
- (TraitObject,
+ }
+ TU_ARMA(TraitObject, te) {
BUG(sp, "Attempting to match a trait object");
- ),
- (ErasedType,
+ }
+ TU_ARMA(ErasedType, te) {
BUG(sp, "Attempting to match an erased type");
- ),
- (Array,
+ }
+ TU_ARMA(Array, te) {
TODO(sp, "Match directly on array?");
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, te) {
ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule);
if( rule.is_Value() ) {
ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]");
@@ -2210,7 +2259,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
auto succ_bb = builder.new_bb_unlinked();
- auto inner_val = val.as_Deref().val->clone();
+ ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val);
+ auto inner_val = val.clone_unwrapped();
auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) });
auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval));
@@ -2223,7 +2273,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2242,7 +2292,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2263,23 +2313,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
else {
BUG(sp, "Invalid rule type for slice - " << rule);
}
- ),
- (Tuple,
+ } // Type::Data::Array
+ TU_ARMA(Tuple, te) {
TODO(sp, "Match directly on tuple?");
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, te) {
TODO(sp, "Match directly on borrow?");
- ), // Type::Data::Borrow
- (Pointer,
+ } // Type::Data::Borrow
+ TU_ARMA(Pointer, te) {
BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty);
- ),
- (Function,
+ }
+ TU_ARMA(Function, te) {
BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty);
- ),
- (Closure,
+ }
+ TU_ARMA(Closure, te) {
BUG(sp, "Attempting to match a closure");
- )
- )
+ }
+ }
}
return 0;
}
@@ -2780,37 +2830,37 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector<t_rules_subset>& rules, s
// Matching over a path can only happen with an enum.
// TODO: What about `box` destructures?
// - They're handled via hidden derefs
- if( !te.binding.is_Enum() ) {
- TU_MATCHA( (te.binding), (pbe),
- (Unbound,
- BUG(sp, "Encounterd unbound path - " << te.path);
- ),
- (Opaque,
- BUG(sp, "Attempting to match over opaque type - " << ty);
- ),
- (Struct,
- const auto& str_data = pbe->m_data;
- TU_MATCHA( (str_data), (sd),
- (Unit,
- BUG(sp, "Attempting to match over unit type - " << ty);
- ),
- (Tuple,
- TODO(sp, "Matching on tuple-like struct?");
- ),
- (Named,
- TODO(sp, "Matching on struct?");
- )
- )
+ TU_MATCH_HDR( (te.binding), { )
+ TU_ARM(te.binding, Unbound, pbe) {
+ BUG(sp, "Encounterd unbound path - " << te.path);
+ }
+ TU_ARM(te.binding, Opaque, pbe) {
+ BUG(sp, "Attempting to match over opaque type - " << ty);
+ }
+ TU_ARM(te.binding, Struct, pbe) {
+ const auto& str_data = pbe->m_data;
+ TU_MATCHA( (str_data), (sd),
+ (Unit,
+ BUG(sp, "Attempting to match over unit type - " << ty);
),
- (Union,
- TODO(sp, "Match over Union");
+ (Tuple,
+ TODO(sp, "Matching on tuple-like struct?");
),
- (Enum,
+ (Named,
+ TODO(sp, "Matching on struct? - " << ty);
)
)
+ }
+ TU_ARM(te.binding, Union, pbe) {
+ TODO(sp, "Match over Union");
+ }
+ TU_ARM(te.binding, ExternType, pbe) {
+ TODO(sp, "Match over ExternType - " << ty);
+ }
+ TU_ARM(te.binding, Enum, pbe) {
+ this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk);
+ }
}
-
- this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk);
),
(Generic,
BUG(sp, "Attempting to match a generic");
@@ -2996,10 +3046,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
}
m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) );
} break;
- case ::HIR::CoreType::Str:
+ case ::HIR::CoreType::Str: {
// Remove the deref on the &str
- auto oval = mv$(val);
- auto val = mv$(*oval.as_Deref().val);
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val);
+ val.m_wrappers.pop_back();
::std::vector< ::MIR::BasicBlockId> targets;
::std::vector< ::std::string> values;
@@ -3023,7 +3073,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
}) );
- break;
+ } break;
}
}
@@ -3061,7 +3111,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c
void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector<t_rules_subset>& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk)
{
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// TODO: Re-sort the rules list to interleve Constant::Bytes and Slice
@@ -3123,8 +3173,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val,
m_builder.set_cur_block(succ_blk);
// TODO: What if `val` isn't a Deref?
- ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings");
- cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val);
+ cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) );
m_builder.set_cur_block(next_cmp_blk);
@@ -3234,7 +3284,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co
ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty);
// Obtain slice length
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// 1. Check that length is sufficient for the pattern to be used
// `IF len < min_len : def_blk, next
diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp
index 38380fed..6f0ef891 100644
--- a/src/mir/helpers.cpp
+++ b/src/mir/helpers.cpp
@@ -12,9 +12,12 @@
#include <mir/mir.hpp>
#include <algorithm> // ::std::find
-void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const
+void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const
{
- os << this->m_path << " BB" << this->bb_idx << "/";
+ if( include_path ) {
+ os << this->m_path << " ";
+ }
+ os << "BB" << this->bb_idx << "/";
if( this->stmt_idx == STMT_TERM ) {
os << "TERM";
}
@@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::function<void(::std::
{
auto& os = ::std::cerr;
os << "MIR " << tag << ": ";
- fmt_pos(os);
+ fmt_pos(os, true);
cb(os);
os << ::std::endl;
abort();
@@ -67,25 +70,39 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c
)
throw "";
}
-const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count/*=0*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ const ::HIR::TypeRef* rv = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
- return m_ret_type;
+ rv = &m_ret_type;
),
(Argument,
- MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
- return m_args.at(e.idx).second;
+ MIR_ASSERT(*this, e < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
+ rv = &m_args.at(e).second;
),
(Local,
MIR_ASSERT(*this, e < m_fcn.locals.size(), "Local " << val << " out of range (" << m_fcn.locals.size() << ")");
- return m_fcn.locals.at(e);
+ rv = &m_fcn.locals.at(e);
),
(Static,
- return get_static_type(tmp, e);
- ),
- (Field,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ rv = &get_static_type(tmp, e);
+ )
+ )
+ assert(wrapper_skip_count <= val.m_wrappers.size());
+ const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ];
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ break;
+ rv = &this->get_unwrapped_type(tmp, w, *rv);
+ }
+ return *rv;
+}
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const
+{
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Field access on unexpected type - " << ty);
@@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- return te[e.field_index];
+ MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ return te[field_index];
),
(Path,
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto monomorph = [&](const auto& ty)->const auto& {
+ auto maybe_monomorph = [&](const auto& ty)->const auto& {
if( monomorphise_type_needed(ty) ) {
tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
m_resolve.expand_associated_types(sp, tmp);
@@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
MIR_BUG(*this, "Field on unit-like struct - " << ty);
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
- return monomorph(se[e.field_index].ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
+ return maybe_monomorph(se[field_index].ent);
),
(Named,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se[e.field_index].second.ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path);
+ return maybe_monomorph(se[field_index].second.ent);
)
)
}
@@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return t;
}
};
- MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent);
+ MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union");
+ return maybe_monomorph(unm.m_variants.at(field_index).second.ent);
}
else
{
@@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- ),
- (Deref,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Deref on unexpected type - " << ty);
@@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Index,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Index, index_local) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Index on unexpected type - " << ty);
@@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Downcast,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Downcast on unexpected type - " << ty);
@@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
const auto& enm = *te.binding.as_Enum();
MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty);
const auto& variants = enm.m_data.as_Data();
- MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty);
- const auto& variant = variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty);
+ const auto& variant = variants[variant_index];
const auto& var_ty = variant.type;
if( monomorphise_type_needed(var_ty) ) {
@@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
else
{
const auto& unm = *te.binding.as_Union();
- MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants[variant_index];
const auto& var_ty = variant.second.ent;
+ //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
if( monomorphise_type_needed(var_ty) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
+ tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
m_resolve.expand_associated_types(sp, tmp);
return tmp;
}
@@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- )
- )
+ }
+ }
throw "";
}
const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const
@@ -270,7 +285,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
),
(Const,
MonomorphState p;
- auto v = m_resolve.get_value(this->sp, e.p, p, /*signature_only=*/true);
+ auto v = m_resolve.get_value(this->sp, *e.p, p, /*signature_only=*/true);
if( const auto* ve = v.opt_Constant() ) {
const auto& ty = (*ve)->m_type;
if( monomorphise_type_needed(ty) ) {
@@ -282,12 +297,12 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
return ty.clone();
}
else {
- MIR_BUG(*this, "get_const_type - Not a constant " << e.p);
+ MIR_BUG(*this, "get_const_type - Not a constant " << *e.p);
}
),
(ItemAddr,
MonomorphState p;
- auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true);
+ auto v = m_resolve.get_value(this->sp, *e, p, /*signature_only=*/true);
TU_MATCHA( (v), (ve),
(NotFound,
MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c);
@@ -325,7 +340,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
::HIR::FunctionType ft;
ft.is_unsafe = false;
ft.m_abi = ABI_RUST;
- auto enum_path = e.clone();
+ auto enum_path = e->clone();
enum_path.m_data.as_Generic().m_path.m_components.pop_back();
ft.m_rettype = box$( ::HIR::TypeRef::new_path(mv$(enum_path), ve.e) );
ft.m_arg_types.reserve(str_data.size());
@@ -348,7 +363,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
::HIR::FunctionType ft;
ft.is_unsafe = false;
ft.m_abi = ABI_RUST;
- ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e.m_data.as_Generic().m_params.clone()), &str) );
+ ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e->m_data.as_Generic().m_params.clone()), &str) );
ft.m_arg_types.reserve(str_data.size());
for(const auto& fld : str_data)
ft.m_arg_types.push_back( p.monomorph(this->sp, fld.ent) );
@@ -383,6 +398,15 @@ namespace visit {
{
if( cb(lv, u) )
return true;
+#if 1
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ cb(LValue::new_Local(w.as_Index()), ValUsage::Read);
+ }
+ }
+#else
TU_MATCHA( (lv), (e),
(Return,
),
@@ -408,6 +432,7 @@ namespace visit {
return visit_mir_lvalue(*e.val, u, cb);
)
)
+#endif
return false;
}
@@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
{
auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) {
// NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime
- if( const auto* de = lv.opt_Local() )
+ if( lv.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = lv.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
+ MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
}
}
- else
- {
- // Not a direct assignment of a slot. But check if a slot is mutated as part of this.
- ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) {
- if( const auto* de = ilv.opt_Local() )
- {
- if( vu == ValUsage::Write )
- {
- if( !mask || mask->at(*de) )
- {
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
- }
- }
- }
- return false;
- });
- }
};
const auto& bb = fcn.blocks[bb_idx];
@@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
else if( const auto* se = stmt.opt_Drop() )
{
// HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator)
- if( const auto* de = se->slot.opt_Local() )
+ if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = se->slot.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
}
}
}
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 58eee9b9..0296a1c4 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -104,7 +104,7 @@ public:
}
unsigned int get_cur_stmt_ofs() const;
- void fmt_pos(::std::ostream& os) const;
+ void fmt_pos(::std::ostream& os, bool include_path=false) const;
void print_bug(::std::function<void(::std::ostream& os)> cb) const {
print_msg("ERROR", cb);
}
@@ -116,7 +116,14 @@ public:
const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const;
const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const;
- const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const;
const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const;
::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const;
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 840db1ac..a0def040 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -6,6 +6,7 @@
* - MIR (Middle Intermediate Representation) definitions
*/
#include <mir/mir.hpp>
+#include <algorithm> // std::min
namespace MIR {
::std::ostream& operator<<(::std::ostream& os, const Constant& v) {
@@ -44,10 +45,10 @@ namespace MIR {
os << "\"" << FmtEscaped(e) << "\"";
),
(Const,
- os << e.p;
+ os << *e.p;
),
(ItemAddr,
- os << "&" << e;
+ os << "&" << *e;
)
)
return os;
@@ -55,7 +56,7 @@ namespace MIR {
::Ordering Constant::ord(const Constant& b) const
{
if( this->tag() != b.tag() )
- return ::ord( static_cast<unsigned int>(this->tag()), b.tag() );
+ return ::ord( static_cast<unsigned int>(this->tag()), static_cast<unsigned int>(b.tag()) );
TU_MATCHA( (*this,b), (ae,be),
(Int,
if( ae.v != be.v )
@@ -82,128 +83,95 @@ namespace MIR {
return ::ord(ae, be);
),
(Const,
- return ::ord(ae.p, be.p);
+ return ::ord(*ae.p, *be.p);
),
(ItemAddr,
- return ::ord(ae, be);
+ return ::ord(*ae, *be);
)
)
throw "";
}
- ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ void LValue::RefCommon::fmt(::std::ostream& os) const
{
- TU_MATCHA( (x), (e),
+ TU_MATCHA( (m_lv->m_root), (e),
(Return,
- os << "Return";
+ os << "retval";
),
(Argument,
- os << "Argument(" << e.idx << ")";
+ os << "a" << e;
),
(Local,
- os << "Local(" << e << ")";
+ os << "_" << e;
),
(Static,
- os << "Static(" << e << ")";
- ),
- (Field,
- os << "Field(" << e.field_index << ", " << *e.val << ")";
- ),
- (Deref,
- os << "Deref(" << *e.val << ")";
- ),
- (Index,
- os << "Index(" << *e.val << ", " << *e.idx << ")";
- ),
- (Downcast,
- os << "Downcast(" << e.variant_index << ", " << *e.val << ")";
+ os << "(" << e << ")";
)
)
+ for(size_t i = 0; i < m_wrapper_count; i ++)
+ {
+ const LValue::Wrapper& w = m_lv->m_wrappers.at(i);
+ TU_MATCHA( (w), (e),
+ (Field,
+ os << "." << e;
+ ),
+ (Deref,
+ os << "*";
+ ),
+ (Index,
+ os << "[_" << e << "]";
+ ),
+ (Downcast,
+ os << "#" << e;
+ )
+ )
+ }
+ }
+
+ ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ {
+ LValue::CRef(x).fmt(os);
return os;
}
- bool operator<(const LValue& a, const LValue& b)
+
+ Ordering LValue::Storage::ord(const LValue::Storage& x) const
{
- if( a.tag() != b.tag() )
- return a.tag() < b.tag();
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return false;
- ),
- (Argument,
- return ea.idx < eb.idx;
- ),
- (Local,
- return ea < eb;
- ),
- (Static,
- return ea < eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- if( ea.field_index != eb.field_index )
- return ea.field_index < eb.field_index;
- return true;
- ),
- (Deref,
- return *ea.val < *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return *ea.idx < *eb.idx;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return ea.variant_index < eb.variant_index;
- )
- )
- throw "";
+ if( x.is_Static() )
+ {
+ if( this->is_Static() )
+ return this->as_Static().ord( x.as_Static() );
+ else
+ return OrdLess;
+ }
+ else
+ {
+ if( this->is_Static() )
+ return OrdGreater;
+ }
+
+ return ::ord(this->val, x.val);
}
- bool operator==(const LValue& a, const LValue& b)
+ Ordering LValue::ord(const LValue& x) const
{
- if( a.tag() != b.tag() )
- return false;
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return true;
- ),
- (Argument,
- return ea.idx == eb.idx;
- ),
- (Local,
- return ea == eb;
- ),
- (Static,
- return ea == eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return false;
- if( ea.field_index != eb.field_index )
- return false;
- return true;
- ),
- (Deref,
- return *ea.val == *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return false;
- if( *ea.idx != *eb.idx )
- return false;
- return true;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return false;
- if( ea.variant_index != eb.variant_index )
- return false;
- return true;
- )
- )
- throw "";
+ auto rv = m_root.ord(x.m_root);
+ if( rv != OrdEqual )
+ return rv;
+ return ::ord(m_wrappers, x.m_wrappers);
+ }
+ Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const
+ {
+ Ordering rv;
+ //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv);
+ rv = m_lv->m_root.ord(x.m_lv->m_root);
+ if( rv != OrdEqual )
+ return rv;
+ for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++)
+ {
+ rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]);
+ if( rv != OrdEqual )
+ return rv;
+ }
+ return (rv = ::ord(m_wrapper_count, x.m_wrapper_count));
}
::std::ostream& operator<<(::std::ostream& os, const Param& x)
@@ -537,30 +505,14 @@ namespace MIR {
}
}
-::MIR::LValue MIR::LValue::clone() const
+::MIR::LValue::Storage MIR::LValue::Storage::clone() const
{
- TU_MATCHA( (*this), (e),
- (Return, return LValue(e); ),
- (Argument, return LValue(e); ),
- (Local, return LValue(e); ),
- (Static, return LValue(e.clone()); ),
- (Field, return LValue::make_Field({
- box$( e.val->clone() ),
- e.field_index
- }); ),
- (Deref, return LValue::make_Deref({
- box$( e.val->clone() )
- }); ),
- (Index, return LValue::make_Index({
- box$( e.val->clone() ),
- box$( e.idx->clone() )
- }); ),
- (Downcast, return LValue::make_Downcast({
- box$( e.val->clone() ),
- e.variant_index
- }); )
- )
- throw "";
+ if( is_Static() ) {
+ return new_Static(as_Static().clone());
+ }
+ else {
+ return Storage(this->val);
+ }
}
::MIR::Constant MIR::Constant::clone() const
{
@@ -571,8 +523,8 @@ namespace MIR {
(Bool, return ::MIR::Constant(e2); ),
(Bytes, return ::MIR::Constant(e2); ),
(StaticString, return ::MIR::Constant(e2); ),
- (Const, return ::MIR::Constant::make_Const({e2.p.clone()}); ),
- (ItemAddr, return ::MIR::Constant(e2.clone()); )
+ (Const, return ::MIR::Constant::make_Const({box$(e2.p->clone())}); ),
+ (ItemAddr, return ::MIR::Constant(box$(e2->clone())); )
)
throw "";
}
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index 31eb9cd7..99698134 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -12,49 +12,395 @@
#include <memory> // std::unique_ptr
#include <hir/type.hpp>
+class MonomorphState;
+
namespace MIR {
typedef unsigned int RegionId;
typedef unsigned int BasicBlockId;
-// "LVALUE" - Assignable values
-TAGGED_UNION_EX(LValue, (), Return, (
- // Function return
- (Return, struct{}),
- // Function argument (input)
- (Argument, struct { unsigned int idx; }),
- // Variable/Temporary
- (Local, unsigned int),
- // `static` or `static mut`
- (Static, ::HIR::Path),
- // Field access (tuple, struct, tuple struct, enum field, ...)
- // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring)
- (Field, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int field_index;
- }),
- // Dereference a value
- (Deref, struct {
- ::std::unique_ptr<LValue> val;
- }),
- // Index an array or slice (typeof(val) == [T; n] or [T])
- // NOTE: This is not bounds checked!
- (Index, struct {
- ::std::unique_ptr<LValue> val;
- ::std::unique_ptr<LValue> idx;
- }),
- // Interpret an enum as a particular variant
- (Downcast, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int variant_index;
- })
- ), (),(), (
- LValue clone() const;
- )
- );
+// Store LValues as:
+// - A packed root value (one word, using the low bits as an enum descriminator)
+// - A list of (inner to outer) wrappers
+struct LValue
+{
+ class Storage
+ {
+ public:
+ const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits
+ private:
+
+ uintptr_t val;
+
+ Storage(uintptr_t v): val(v) {}
+ public:
+ Storage(const Storage&) = delete;
+ Storage& operator=(const Storage&) = delete;
+ Storage(Storage&& x)
+ :val(x.val)
+ {
+ x.val = 0;
+ }
+ Storage& operator=(Storage&& x)
+ {
+ this->~Storage();
+ this->val = x.val;
+ x.val = 0;
+ return *this;
+ }
+ ~Storage()
+ {
+ if( is_Static() ) {
+ delete reinterpret_cast<::HIR::Path*>(val & ~3ull);
+ val = 0;
+ }
+ }
+
+ static Storage new_Return() { return Storage(0 << 2); }
+ static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); }
+ static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); }
+ static Storage new_Static(::HIR::Path p) {
+ ::HIR::Path* ptr = new ::HIR::Path(::std::move(p));
+ return Storage(reinterpret_cast<uintptr_t>(ptr) | 2);
+ }
+
+ Storage clone() const;
+
+ uintptr_t get_inner() const {
+ assert(!is_Static());
+ return val;
+ }
+ static Storage from_inner(uintptr_t v) {
+ assert( (v & 3) < 2 );
+ return Storage(v);
+ }
+
+ enum Tag {
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Return,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ if(val == 0)
+ return TAG_Return;
+ return static_cast<Tag>(val & 3);
+ }
+
+ bool is_Return() const { return val == 0; }
+ bool is_Argument() const { return val != 0 && (val & 3) == 0; }
+ bool is_Local() const { return (val & 3) == 1; }
+ bool is_Static() const { return (val & 3) == 2; }
+
+ const char as_Return () const { assert(is_Return()); return 0; }
+ const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; }
+ const unsigned as_Local () const { assert(is_Local()); return val >> 2; }
+
+ const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast<const ::HIR::Path*>(val & ~3llu); }
+ ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); }
+
+ Ordering ord(const Storage& x) const;
+ bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; }
+ bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; }
+ };
+ class Wrapper
+ {
+ uint32_t val;
+ Wrapper(uint32_t v): val(v) {}
+ public:
+ static Wrapper new_Deref() { return Wrapper( 0 ); }
+ static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); }
+ static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); }
+ static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); }
+
+ uint32_t get_inner() const { return val; }
+ static Wrapper from_inner(uint32_t v) {
+ return Wrapper(v);
+ }
+
+ enum Tag {
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ return static_cast<Tag>(val & 3);
+ }
+
+ bool is_Deref () const { return (val & 3) == 0; }
+ // Stores the field index
+ bool is_Field () const { return (val & 3) == 1; }
+ // Stores the variant index
+ bool is_Downcast() const { return (val & 3) == 2; }
+ // Stores a Local index
+ bool is_Index () const { return (val & 3) == 3; }
+
+ const char as_Deref () const { assert(is_Deref()); return 0; }
+ const unsigned as_Field () const { assert(is_Field()); return (val >> 2); }
+ const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); }
+ // TODO: Should this return a LValue?
+ const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; }
+
+ void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); }
+ void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); }
+
+ Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); }
+ };
+
+ Storage m_root;
+ ::std::vector<Wrapper> m_wrappers;
+
+ LValue()
+ :m_root( Storage::new_Return() )
+ {
+ }
+ LValue(Storage root, ::std::vector<Wrapper> wrappers)
+ :m_root( ::std::move(root) )
+ ,m_wrappers( ::std::move(wrappers) )
+ {
+ }
+
+ static LValue new_Return () { return LValue(Storage::new_Return(), {}); }
+ static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); }
+ static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); }
+ static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); }
+
+ static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; }
+ static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; }
+ static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; }
+ static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; }
+
+ bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); }
+ bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); }
+ const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); }
+
+ bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); }
+ bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); }
+ bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); }
+ const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); }
+
+ void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); }
+ void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); }
+
+ Ordering ord(const LValue& x) const;
+
+ LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0);
+ //LValue monomorphise(const TransParams& ms, unsigned local_offset=0);
+ LValue clone() const {
+ return LValue(m_root.clone(), m_wrappers);
+ }
+ LValue clone_wrapped(::std::vector<Wrapper> wrappers) const {
+ if( this->m_wrappers.empty() ) {
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+ else {
+ return clone_wrapped(wrappers.begin(), wrappers.end());
+ }
+ }
+ template<typename It>
+ LValue clone_wrapped(It begin_it, It end_it) const {
+ ::std::vector<Wrapper> wrappers;
+ wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it));
+ wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end());
+ wrappers.insert(wrappers.end(), begin_it, end_it);
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+
+ LValue clone_unwrapped(unsigned count=1) const {
+ assert(count > 0);
+ assert(count <= m_wrappers.size());
+ return LValue(m_root.clone(), ::std::vector<Wrapper>(m_wrappers.begin(), m_wrappers.end() - count));
+ }
+
+ /// Helper class that represents a LValue unwrapped to a certain degree
+ class RefCommon
+ {
+ protected:
+ const LValue* m_lv;
+ size_t m_wrapper_count;
+
+ RefCommon(const LValue& lv, size_t wrapper_count)
+ :m_lv(&lv)
+ ,m_wrapper_count(wrapper_count)
+ {
+ assert(wrapper_count <= lv.m_wrappers.size());
+ }
+
+ public:
+ LValue clone() const {
+ return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector<Wrapper>(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) );
+ }
+
+ const LValue& lv() const { return *m_lv; }
+ size_t wrapper_count() const { return m_wrapper_count; }
+
+ /// Unwrap one level, returning false if already at the root
+ bool try_unwrap() {
+ if( m_wrapper_count == 0 ) {
+ return false;
+ }
+ else {
+ m_wrapper_count --;
+ return true;
+ }
+ }
+
+ enum Tag {
+ TAGDEAD,
+ TAG_Return,
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ };
+ Tag tag() const {
+ if( m_wrapper_count == 0 )
+ {
+ switch(m_lv->m_root.tag())
+ {
+ case Storage::TAGDEAD: return TAGDEAD;
+ case Storage::TAG_Return: return TAG_Return;
+ case Storage::TAG_Argument: return TAG_Argument;
+ case Storage::TAG_Local: return TAG_Local;
+ case Storage::TAG_Static: return TAG_Static;
+ }
+ }
+ else
+ {
+ switch(m_lv->m_wrappers[m_wrapper_count-1].tag())
+ {
+ case Wrapper::TAGDEAD: return TAGDEAD;
+ case Wrapper::TAG_Deref: return TAG_Deref;
+ case Wrapper::TAG_Field: return TAG_Field;
+ case Wrapper::TAG_Downcast: return TAG_Downcast;
+ case Wrapper::TAG_Index: return TAG_Index;
+ }
+ }
+ return TAGDEAD;
+ }
+
+ bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); }
+ bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); }
+ bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); }
+ bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); }
+ bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); }
+ bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); }
+ bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); }
+ bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); }
+
+ const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); }
+ const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); }
+ const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); }
+ const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); }
+ const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); }
+ const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); }
+ const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); }
+ const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); }
+
+ void fmt(::std::ostream& os) const;
+ Ordering ord(const RefCommon& b) const;
+ };
+
+ class CRef: public RefCommon
+ {
+ public:
+ CRef(const LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+ CRef(const LValue& lv, size_t wc)
+ :RefCommon(lv, wc)
+ {
+ }
+
+ /// Unwrap one level
+ const CRef inner_ref() const {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) {
+ x.fmt(os);
+ return os;
+ }
+
+ bool operator<(const CRef& b) const {
+ return this->ord(b) == OrdLess;
+ }
+ bool operator==(const CRef& b) const {
+ return this->ord(b) == OrdEqual;
+ }
+ };
+ class MRef: public RefCommon
+ {
+ public:
+ MRef(LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+
+ operator CRef() const {
+ return CRef(*m_lv, m_wrapper_count);
+ }
+
+ MRef inner_ref() {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+ void replace(LValue x) {
+ auto& mut_lv = const_cast<LValue&>(*m_lv);
+ // Shortcut: No wrappers on source/destination (just assign the slot/root)
+ if( m_wrapper_count == 0 && x.m_wrappers.empty() ) {
+ mut_lv.m_root = ::std::move(x.m_root);
+ return ;
+ }
+ // If there's wrappers on this value (assigning over inner portion)
+ if( m_wrapper_count < m_lv->m_wrappers.size() ) {
+ // Add those wrappers to the end of the new value
+ x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end());
+ }
+ // Overwrite
+ mut_lv = ::std::move(x);
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) {
+ x.fmt(os);
+ return os;
+ }
+ };
+
+ Ordering ord(const LValue::CRef& x) const;
+ Ordering ord(const LValue::MRef& x) const;
+};
extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x);
-extern bool operator<(const LValue& a, const LValue& b);
-extern bool operator==(const LValue& a, const LValue& b);
+static inline bool operator<(const LValue& a, const LValue::CRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue& a, const LValue::MRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue::CRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue::MRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator==(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdEqual;
+}
static inline bool operator!=(const LValue& a, const LValue& b) {
return !(a == b);
}
@@ -103,8 +449,10 @@ TAGGED_UNION_EX(Constant, (), Int, (
}),
(Bytes, ::std::vector< ::std::uint8_t>), // Byte string
(StaticString, ::std::string), // String
- (Const, struct { ::HIR::Path p; }), // `const`
- (ItemAddr, ::HIR::Path) // address of a value
+ // NOTE: These are behind pointers to save inline space (HIR::Path is ~11
+ // words, compared to 4 for MIR::Constant without it)
+ (Const, struct { ::std::unique_ptr<::HIR::Path> p; }), // `const`
+ (ItemAddr, ::std::unique_ptr<::HIR::Path>) // address of a value
), (), (), (
friend ::std::ostream& operator<<(::std::ostream& os, const Constant& v);
::Ordering ord(const Constant& b) const;
@@ -120,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, (
/// Parameter - A value used when a rvalue just reads (doesn't require a lvalue)
/// Can be either a lvalue (memory address), or a constant
-TAGGED_UNION_EX(Param, (), LValue, (
+TAGGED_UNION_EX(Param, (), Constant, (
(LValue, LValue),
(Constant, Constant)
), (), (), (
@@ -133,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, (
)
);
-TAGGED_UNION_EX(RValue, (), Use, (
+TAGGED_UNION_EX(RValue, (), Tuple, (
(Use, LValue),
(Constant, Constant),
(SizedArray, struct {
@@ -207,7 +555,7 @@ TAGGED_UNION(CallTarget, Intrinsic,
(Value, LValue),
(Path, ::HIR::Path),
(Intrinsic, struct {
- ::std::string name;
+ RcString name;
::HIR::PathParams params;
})
);
@@ -255,7 +603,7 @@ enum class eDropKind {
SHALLOW,
DEEP,
};
-TAGGED_UNION(Statement, Assign,
+TAGGED_UNION(Statement, Asm,
// Value assigment
(Assign, struct {
LValue dst;
@@ -298,14 +646,30 @@ struct BasicBlock
};
+struct EnumCache; // Defined in trans/enumerate.cpp
+class EnumCachePtr
+{
+ const EnumCache* p;
+public:
+ EnumCachePtr(const EnumCache* p=nullptr): p(p) {}
+ ~EnumCachePtr();
+ EnumCachePtr(EnumCachePtr&& x): p(x.p) { x.p = nullptr; }
+ EnumCachePtr& operator=(EnumCachePtr&& x) { this->~EnumCachePtr(); p = x.p; x.p = nullptr; return *this; }
+ operator bool() { return p != nullptr; }
+ const EnumCache& operator*() const { return *p; }
+ const EnumCache* operator->() const { return p; }
+};
class Function
{
public:
::std::vector< ::HIR::TypeRef> locals;
- //::std::vector< ::std::string> local_names;
+ //::std::vector< RcString> local_names;
::std::vector<bool> drop_flags;
::std::vector<BasicBlock> blocks;
+
+ // Cache filled/used by enumerate
+ mutable EnumCachePtr trans_enum_state;
};
};
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 3e14ce66..96833609 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -68,7 +68,7 @@ MirBuilder::~MirBuilder()
{
if( has_result() )
{
- push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) );
+ push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) );
}
terminate_scope_early(sp, fcn_scope());
@@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx)
auto& tmp_scope = top_scope->data.as_Owning();
assert(tmp_scope.is_temporary);
tmp_scope.slots.push_back( rv );
- return ::MIR::LValue::make_Local(rv);
+ return ::MIR::LValue::new_Local(rv);
}
::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val)
{
@@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val)
m_result_valid = true;
}
-void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val)
+void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/)
{
DEBUG(dst << " = " << val);
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, "");
- ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, "");
auto moved_param = [&](const ::MIR::Param& p) {
if(const auto* e = p.opt_LValue()) {
@@ -340,13 +338,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal
)
// Drop target if populated
- mark_value_assigned(sp, dst);
+ if( drop_destination )
+ {
+ mark_value_assigned(sp, dst);
+ }
this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) );
}
void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
if( lvalue_is_copy(sp, val) ) {
// Don't emit a drop for Copy values
@@ -358,7 +358,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int
void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
// TODO: Ensure that the type is a Box?
@@ -396,21 +395,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt)
void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
{
- VarState* state_p = nullptr;
- TU_MATCH_DEF(::MIR::LValue, (dst), (e),
- (
- ),
- (Return,
- // Don't drop.
- // No state tracking for the return value
- ),
- (Argument,
- state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument);
- ),
- (Local,
- state_p = &get_slot_state_mut(sp, e, SlotType::Local);
- )
- )
+ if( dst.m_root.is_Return() )
+ {
+ ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible.");
+ return ;
+ }
+ VarState* state_p = get_val_state_mut_p(sp, dst, /*expect_valid=*/true);
if( state_p )
{
@@ -420,41 +410,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
drop_value_from_state(sp, *state_p, dst.clone());
*state_p = VarState::make_Valid({});
}
+ else
+ {
+ // Assigning into non-tracked locations still causes a drop
+ drop_value_from_state(sp, VarState::make_Valid({}), dst.clone());
+ }
}
void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/)
{
TRACE_FUNCTION_F(val);
- TU_MATCH_DEF(::MIR::LValue, (val), (e),
- (
+ for(const auto& w : val.m_wrappers)
+ {
+ if( w.is_Index() ) {
+ // Raise index temporary
+ raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above);
+ }
+ }
+ if( !val.m_root.is_Local() ) {
// No raising of these source values?
return ;
- ),
- // TODO: This may not be correct, because it can change the drop points and ordering
- // HACK: Working around cases where values are dropped while the result is not yet used.
- (Index,
- raise_temporaries(sp, *e.val, scope, to_above);
- raise_temporaries(sp, *e.idx, scope, to_above);
- return ;
- ),
- (Deref,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Field,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Downcast,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- // Actual value types
- (Local,
- )
- )
- ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val);
- const auto idx = val.as_Local();
+ }
+ const auto idx = val.m_root.as_Local();
bool is_temp = (idx >= m_first_temp_idx);
/*
if( !is_temp ) {
@@ -827,13 +804,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
}
auto& src_scope_def = m_scopes.at(source.idx);
-#if 1
ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)");
ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)");
auto& src_list = src_scope_def.data.as_Owning().slots;
for(auto idx : src_list)
{
- DEBUG("> Raising " << ::MIR::LValue::make_Local(idx));
+ DEBUG("> Raising " << ::MIR::LValue::new_Local(idx));
assert(idx >= m_first_temp_idx);
}
@@ -904,13 +880,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
// Move all defined variables from one to the other
auto& tgt_list = tgt_scope_def.data.as_Owning().slots;
tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() );
-#else
- auto list = src_scope_def.data.as_Temporaries().temporaries;
- for(auto idx : list)
- {
- this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target);
- }
-#endif
// Scope completed
m_scope_stack.pop_back();
@@ -973,7 +942,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope,
for(size_t i = 0; i < m_arg_states.size(); i ++)
{
const auto& state = get_slot_state(sp, i, SlotType::Argument);
- this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) }));
+ this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast<unsigned>(i)));
}
}
}
@@ -1054,7 +1023,7 @@ namespace
});
if( is_box )
{
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else
{
@@ -1080,13 +1049,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return;
@@ -1162,7 +1131,7 @@ namespace
});
if( is_box ) {
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else {
BUG(sp, "MovedOut on non-Box");
@@ -1186,19 +1155,19 @@ namespace
}
auto& ose = old_state.as_Partial();
if( is_enum ) {
- auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0);
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Downcast().variant_index ++;
+ ilv.inc_Downcast();
}
}
else {
- auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0);
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Field().field_index ++;
+ ilv.inc_Field();
}
}
} return;
@@ -1262,13 +1231,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
return; }
@@ -1303,7 +1272,7 @@ namespace
builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return ; }
case VarState::TAG_Optional: {
const auto& nse = new_state.as_Optional();
@@ -1328,7 +1297,7 @@ namespace
builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse);
builder.push_stmt_set_dropflag_default(sp, nse);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return; }
case VarState::TAG_MovedOut: {
const auto& nse = new_state.as_MovedOut();
@@ -1336,7 +1305,7 @@ namespace
{
TODO(sp, "Handle mismatched flags in MovedOut");
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
return; }
case VarState::TAG_Partial:
BUG(sp, "MovedOut->Partial not valid");
@@ -1360,13 +1329,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], new_state);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state);
}
}
return ;
@@ -1378,13 +1347,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return ;
@@ -1413,8 +1382,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l
merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type));
}
};
- merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local);
- merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument);
+ merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local);
+ merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument);
}
else
{
@@ -1469,7 +1438,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
auto it = states.find(idx);
const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1));
- auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx}));
+ auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx));
merge_state(sp, *this, mv$(lv), out_state, src_state);
}
};
@@ -1548,7 +1517,6 @@ void MirBuilder::complete_scope(ScopeDef& sd)
(Split,
),
(Freeze,
- //DEBUG("Freeze");
)
)
@@ -1560,7 +1528,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1569,7 +1537,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1601,26 +1569,50 @@ void MirBuilder::complete_scope(ScopeDef& sd)
ASSERT_BUG(sd.span, e.end_state_valid, "");
H::apply_end_state(sd.span, *this, e.end_state);
}
+ else if( const auto* e = sd.data.opt_Freeze() )
+ {
+ TRACE_FUNCTION_F("Freeze");
+ for(auto& ent : e->changed_slots)
+ {
+ auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local);
+ auto lv = ::MIR::LValue::new_Local(ent.first);
+ DEBUG(lv << " " << vs << " => " << ent.second);
+ if( vs != ent.second )
+ {
+ if( vs.is_Valid() ) {
+ ERROR(sd.span, E0000, "Value went from " << vs << " => " << ent.second << " over freeze");
+ }
+ else if( !this->lvalue_is_copy(sd.span, lv) ) {
+ ERROR(sd.span, E0000, "Non-Copy value went from " << vs << " => " << ent.second << " over freeze");
+ }
+ else {
+ // It's a Copy value, and it wasn't originally fully Valid - allowable
+ }
+ }
+ }
+ }
}
-void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const
+void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ ::HIR::TypeRef tmp;
+ const ::HIR::TypeRef* ty_p = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
TODO(sp, "Return");
),
(Argument,
- cb( m_args.at(e.idx).second );
+ ty_p = &m_args.at(e).second;
),
(Local,
- cb( m_output.locals.at(e) );
+ ty_p = &m_output.locals.at(e);
),
(Static,
TU_MATCHA( (e.m_data), (pe),
(Generic,
ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static");
const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path);
- cb( s.m_type );
+ ty_p = &s.m_type;
),
(UfcsKnown,
TODO(sp, "Static - UfcsKnown - " << e);
@@ -1632,68 +1624,65 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
TODO(sp, "Static - UfcsInherent - " << e);
)
)
- ),
- (Field,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ )
+ )
+ assert(ty_p);
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ {
+ stop_wrapper = nullptr; // Reset so the below bugcheck can work
+ break;
+ }
+ const auto& ty = *ty_p;
+ ty_p = nullptr;
+ auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
+ if( monomorphise_type_needed(t) ) {
+ tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return t;
+ }
+ };
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Field access on unexpected type - " << ty);
),
(Array,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Slice,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Path,
- ::HIR::TypeRef tmp;
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
TU_MATCHA( (str.m_data), (se),
(Unit,
BUG(sp, "Field on unit-like struct - " << ty);
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index];
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index];
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
),
(Named,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index].second;
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index].second;
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
)
)
}
- else if( const auto* tep = te.binding.opt_Union() )
+ else if( /*const auto* tep =*/ te.binding.opt_Union() )
{
BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty);
- const auto& unm = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
- ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) );
}
else
{
@@ -1701,14 +1690,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- cb( te[e.field_index] );
+ ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ ty_p = &te[field_index];
)
)
- });
- ),
- (Deref,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Deref on unexpected type - " << ty);
@@ -1716,38 +1703,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
(Path,
if( const auto* inner_ptr = this->is_type_owned_box(ty) )
{
- cb( *inner_ptr );
+ ty_p = &*inner_ptr;
}
else {
BUG(sp, "Deref on unexpected type - " << ty);
}
),
(Pointer,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Borrow,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Index,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Index, _index_val) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Index on unexpected type - " << ty);
),
(Slice,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Array,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Downcast,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Downcast on unexpected type - " << ty);
@@ -1758,33 +1741,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
const auto& enm = **pbe;
ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum");
const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range");
- const auto& variant = variants[e.variant_index];
+ ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range");
+ const auto& variant = variants[variant_index];
- if( monomorphise_type_needed(variant.type) ) {
- auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type);
- m_resolve.expand_associated_types(sp, tmp);
- cb(tmp);
- }
- else {
- cb(variant.type);
- }
+ ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type);
}
else if( const auto* pbe = te.binding.opt_Union() )
{
const auto& unm = **pbe;
- ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants.at(e.variant_index);
+ ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants.at(variant_index);
const auto& fld = variant.second;
- if( monomorphise_type_needed(fld.ent) ) {
- auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent);
- m_resolve.expand_associated_types(sp, sty);
- cb(sty);
- }
- else {
- cb(fld.ent);
- }
+ ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent);
}
else
{
@@ -1792,9 +1761,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
)
)
- });
- )
- )
+ }
+ }
+ assert(ty_p);
+ }
+ ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found");
+ cb(*ty_p);
}
bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const
@@ -1913,20 +1885,38 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
}
- else if( scope_def.data.is_Freeze() )
+ // Freeze is used for `match` guards
+ // - These are only allowed to modify the (known `bool`) condition variable
+ // TODO: Some guards have more complex pieces of code, with self-contained scopes, allowable?
+ // - Those should already have defined their own scope?
+ // - OR, allow mutations here but ONLY if it's of a Copy type, and force it uninit at the end of the scope
+ else if( auto* e = scope_def.data.opt_Freeze() )
{
+ // If modified variable is the guard's result variable, allow it.
+ if( type != SlotType::Local ) {
+ DEBUG("Mutating state of arg" << idx);
+ ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ }
if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() )
{
+ // The guard condition variable is allowed to be mutated, and falls through to the upper scope
}
else
{
- // NOTE: This is only used in match conditions
- DEBUG("Mutating state of ?" << idx);
- ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ DEBUG("Mutating state of local" << idx);
+ auto& states = e->changed_slots;
+ if( states.count(idx) == 0 )
+ {
+ auto state = get_slot_state(sp, idx, type).clone();
+ states.insert(::std::make_pair( idx, mv$(state) ));
+ }
+ ret = &states[idx];
+ break; // Stop searching
}
}
else
{
+ // Unknown scope type?
}
}
if( ret )
@@ -1953,165 +1943,171 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
-const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count)
-{
- TODO(sp, "");
-}
-VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
+VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv, bool expect_valid/*=false*/)
{
TRACE_FUNCTION_F(lv);
- TU_MATCHA( (lv), (e),
+ VarState* vs;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
BUG(sp, "Move of return value");
- return get_slot_state_mut(sp, ~0u, SlotType::Local);
+ vs = &get_slot_state_mut(sp, ~0u, SlotType::Local);
),
(Argument,
- return get_slot_state_mut(sp, e.idx, SlotType::Argument);
+ vs = &get_slot_state_mut(sp, e, SlotType::Argument);
),
(Local,
- return get_slot_state_mut(sp, e, SlotType::Local);
+ vs = &get_slot_state_mut(sp, e, SlotType::Local);
),
(Static,
- BUG(sp, "Attempting to mutate state of a static");
- ),
- (Field,
- auto& ivs = get_val_state_mut(sp, *e.val);
- VarState tpl;
- TU_MATCHA( (ivs), (ivse),
- (Invalid,
- //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
- tpl = VarState::make_Valid({});
- ),
- (MovedOut,
- BUG(sp, "Field on value with MovedOut state - " << lv);
- ),
- (Partial,
- ),
- (Optional,
- tpl = ivs.clone();
- ),
- (Valid,
- tpl = VarState::make_Valid({});
- )
+ return nullptr;
+ //BUG(sp, "Attempting to mutate state of a static");
)
- if( !ivs.is_Partial() )
- {
- size_t n_flds = 0;
- with_val_type(sp, *e.val, [&](const auto& ty) {
- DEBUG("ty = " << ty);
- if(const auto* e = ty.m_data.opt_Path()) {
- ASSERT_BUG(sp, e->binding.is_Struct(), "");
- const auto& str = *e->binding.as_Struct();
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(sp, "Field access of unit-like struct");
- ),
- (Tuple,
- n_flds = se.size();
- ),
- (Named,
- n_flds = se.size();
- )
- )
- }
- else if(const auto* e = ty.m_data.opt_Tuple()) {
- n_flds = e->size();
- }
- else if(const auto* e = ty.m_data.opt_Array()) {
- n_flds = e->size_val;
- }
- else {
- TODO(sp, "Determine field count for " << ty);
- }
- });
- ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
- for(size_t i = 0; i < n_flds; i++)
- inner_vs.push_back( tpl.clone() );
- ivs = VarState::make_Partial({ mv$(inner_vs) });
- }
- return ivs.as_Partial().inner_states.at(e.field_index);
- ),
- (Deref,
- // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
- bool is_box = false;
- if( this->m_lang_Box )
- {
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- is_box = this->is_type_owned_box(ty);
- });
- }
+ )
+ if( expect_valid && vs->is_Valid() )
+ {
+ return nullptr;
+ }
- if( is_box )
- {
- auto& ivs = get_val_state_mut(sp, *e.val);
- if( ! ivs.is_MovedOut() )
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& ivs = *vs;
+ vs = nullptr;
+ TU_MATCH_HDRA( (w), { )
+ TU_ARMA(Field, field_index) {
+ VarState tpl;
+ TU_MATCHA( (ivs), (ivse),
+ (Invalid,
+ //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
+ tpl = VarState::make_Valid({});
+ ),
+ (MovedOut,
+ BUG(sp, "Field on value with MovedOut state - " << lv);
+ ),
+ (Partial,
+ ),
+ (Optional,
+ tpl = ivs.clone();
+ ),
+ (Valid,
+ tpl = VarState::make_Valid({});
+ )
+ )
+ if( !ivs.is_Partial() )
{
- ::std::vector<VarState> inner;
- inner.push_back(VarState::make_Valid({}));
- unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
- ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
+ size_t n_flds = 0;
+ with_val_type(sp, lv, [&](const auto& ty) {
+ DEBUG("ty = " << ty);
+ if(const auto* e = ty.m_data.opt_Path()) {
+ ASSERT_BUG(sp, e->binding.is_Struct(), "");
+ const auto& str = *e->binding.as_Struct();
+ TU_MATCHA( (str.m_data), (se),
+ (Unit,
+ BUG(sp, "Field access of unit-like struct");
+ ),
+ (Tuple,
+ n_flds = se.size();
+ ),
+ (Named,
+ n_flds = se.size();
+ )
+ )
+ }
+ else if(const auto* e = ty.m_data.opt_Tuple()) {
+ n_flds = e->size();
+ }
+ else if(const auto* e = ty.m_data.opt_Array()) {
+ n_flds = e->size_val;
+ }
+ else {
+ TODO(sp, "Determine field count for " << ty);
+ }
+ }, &w);
+ ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
+ for(size_t i = 0; i < n_flds; i++)
+ inner_vs.push_back( tpl.clone() );
+ ivs = VarState::make_Partial({ mv$(inner_vs) });
+ }
+ vs = &ivs.as_Partial().inner_states.at(field_index);
+ }
+ TU_ARMA(Deref, _e) {
+ // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
+ bool is_box = false;
+ if( this->m_lang_Box )
+ {
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ is_box = this->is_type_owned_box(ty);
+ }, &w);
}
- return *ivs.as_MovedOut().inner_state;
- }
- else
- {
- BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<<ty;});) );
- }
- ),
- (Index,
- BUG(sp, "Move out of index with non-Copy values - Partial move?");
- ),
- (Downcast,
- // TODO: What if the inner is Copy? What if the inner is a hidden pointer?
- auto& ivs = get_val_state_mut(sp, *e.val);
- //static VarState ivs; ivs = VarState::make_Valid({});
- if( !ivs.is_Partial() )
- {
- ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
-
- size_t var_count = 0;
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
- const auto& pb = ty.m_data.as_Path().binding;
- // TODO: What about unions?
- // - Iirc, you can't move out of them so they will never have state mutated
- if( pb.is_Enum() )
- {
- const auto& enm = *pb.as_Enum();
- var_count = enm.num_variants();
- }
- else if( const auto* pbe = pb.opt_Union() )
+
+ if( is_box )
+ {
+ if( ! ivs.is_MovedOut() )
{
- const auto& unm = **pbe;
- var_count = unm.m_variants.size();
+ ::std::vector<VarState> inner;
+ inner.push_back(VarState::make_Valid({}));
+ unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
+ ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
}
- else
+ vs = &*ivs.as_MovedOut().inner_state;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+ TU_ARMA(Index, e) {
+ return nullptr;
+ }
+ TU_ARMA(Downcast, variant_index) {
+ if( !ivs.is_Partial() )
+ {
+ ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
+
+ size_t var_count = 0;
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
+ const auto& pb = ty.m_data.as_Path().binding;
+ // TODO: What about unions?
+ // - Iirc, you can't move out of them so they will never have state mutated
+ if( pb.is_Enum() )
+ {
+ const auto& enm = *pb.as_Enum();
+ var_count = enm.num_variants();
+ }
+ else if( const auto* pbe = pb.opt_Union() )
+ {
+ const auto& unm = **pbe;
+ var_count = unm.m_variants.size();
+ }
+ else
+ {
+ BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ }
+ }, &w);
+
+ ::std::vector<VarState> inner;
+ for(size_t i = 0; i < var_count; i ++)
{
- BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
}
- });
+ inner[variant_index] = mv$(ivs);
+ ivs = VarState::make_Partial({ mv$(inner) });
+ }
- ::std::vector<VarState> inner;
- for(size_t i = 0; i < var_count; i ++)
- {
- inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
+ vs = &ivs.as_Partial().inner_states.at(variant_index);
}
- inner[e.variant_index] = mv$(ivs);
- ivs = VarState::make_Partial({ mv$(inner) });
}
-
- return ivs.as_Partial().inner_states.at(e.variant_index);
- )
- )
- BUG(sp, "Fell off send of get_val_state_mut");
+ assert(vs);
+ }
+ return vs;
}
-
void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv)
{
+ TRACE_FUNCTION_F(lv << " " << vs);
TU_MATCHA( (vs), (vse),
(Invalid,
),
@@ -2125,7 +2121,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
});
if( is_box )
{
- drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::make_Deref({ box$(lv.clone()) }));
+ drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::new_Deref(lv.clone()));
push_stmt_drop_shallow(sp, mv$(lv), vse.outer_flag);
}
else
@@ -2145,7 +2141,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
DEBUG("TODO: Switch based on enum value");
//for(size_t i = 0; i < vse.inner_states.size(); i ++)
//{
- // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)));
//}
}
else if( is_union )
@@ -2156,7 +2152,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
{
for(size_t i = 0; i < vse.inner_states.size(); i ++)
{
- drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Field({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Field(lv.clone(), static_cast<unsigned int>(i)));
}
}
),
@@ -2174,7 +2170,7 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
{
const auto& vs = get_slot_state(sd.span, idx, SlotType::Local);
DEBUG("slot" << idx << " - " << vs);
- drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) );
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::new_Local(idx) );
}
),
(Split,
@@ -2192,24 +2188,28 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv)
{
if( !lvalue_is_copy(sp, lv) ) {
- auto& vs = get_val_state_mut(sp, lv);
+ auto* vs_p = get_val_state_mut_p(sp, lv);
+ if( !vs_p ) {
+ ERROR(sp, E0000, "Attempting to move out of invalid slot - " << lv);
+ }
+ auto& vs = *vs_p;
// TODO: If the current state is Optional, set the drop flag to 0
vs = VarState::make_Invalid(InvalidType::Moved);
}
}
-const ::MIR::LValue& MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
+::MIR::LValue MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
{
// Undo field accesses
- const auto* lvp = &lv;
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
+ size_t count = 0;
+ while( count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Field() )
+ count ++;
// TODO: Enum variants?
- ASSERT_BUG(sp, lvp->is_Deref(), "Access of an unsized field without a dereference - " << lv);
+ ASSERT_BUG(sp, count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Deref(), "Access of an unsized field without a dereference - " << lv);
- return *lvp->as_Deref().val;
+ return lv.clone_unwrapped(count+1);
}
// --------------------------------------------------------------------
@@ -2253,7 +2253,7 @@ VarState VarState::clone() const
)
throw "";
}
-bool VarState::operator==(VarState& x) const
+bool VarState::operator==(const VarState& x) const
{
if( this->tag() != x.tag() )
return false;
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/mir/optimise.cpp b/src/mir/optimise.cpp
index 80bca08d..04ba8470 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -191,7 +191,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
#endif
// >> Move common statements (assignments) across gotos.
- change_happened |= MIR_Optimise_CommonStatements(state, fcn);
+ //change_happened |= MIR_Optimise_CommonStatements(state, fcn);
// >> Combine Duplicate Blocks
change_happened |= MIR_Optimise_UnifyBlocks(state, fcn);
@@ -305,49 +305,78 @@ namespace {
Borrow, // Any borrow
};
- bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues_inner(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
{
- //TRACE_FUNCTION_F(lv);
- if( cb(lv, u) )
- return true;
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- ),
- (Field,
- // HACK: If "moving", use a "Read" value usage (covers some quirks)
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Move ? ValUsage::Read : u, cb);
- ),
- (Deref,
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Borrow ? u : ValUsage::Read, cb);
- ),
- (Index,
- bool rv = false;
- rv |= visit_mir_lvalue_mut(*e.val, u, cb);
- rv |= visit_mir_lvalue_mut(*e.idx, ValUsage::Read, cb);
- return rv;
- ),
- (Downcast,
- return visit_mir_lvalue_mut(*e.val, u, cb);
- )
- )
+ for(const auto& w : lv.m_wrappers)
+ {
+ if(w.is_Index())
+ {
+ if( cb(::MIR::LValue::new_Local(w.as_Index()), ValUsage::Read) )
+ return true;
+ }
+ else if(w.is_Deref())
+ {
+ //u = ValUsage::Read;
+ }
+ }
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue::MRef& , ValUsage)> cb)
+ {
+ auto lvr = ::MIR::LValue::MRef(lv);
+ do
+ {
+ if( cb(lvr, u) )
+ return true;
+ // TODO: Use a TU_MATCH?
+ if( lvr.is_Index() )
+ {
+ auto ilv = ::MIR::LValue::new_Local(lvr.as_Index());
+ auto ilv_r = ::MIR::LValue::MRef(ilv);
+ bool rv = cb(ilv_r, ValUsage::Read);
+ assert(ilv.is_Local() && ilv.as_Local() == lvr.as_Index());
+ if( rv )
+ return true;
+ }
+ else if( lvr.is_Field() )
+ {
+ // HACK: If "moving", use a "Read" value usage (covers some quirks)
+ if( u == ValUsage::Move ) {
+ u = ValUsage::Read;
+ }
+ }
+ else if( lvr.is_Deref() )
+ {
+ // TODO: Is this right?
+ if( u == ValUsage::Borrow ) {
+ u = ValUsage::Read;
+ }
+ }
+ else
+ {
+ // No change
+ }
+ } while( lvr.try_unwrap() );
return false;
}
- bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue::CRef& , ValUsage)> cb)
{
return visit_mir_lvalue_mut( const_cast<::MIR::LValue&>(lv), u, [&](auto& v, auto u) { return cb(v,u); } );
}
+ bool visit_mir_lvalue_raw_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_raw(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
bool visit_mir_lvalue_mut(::MIR::Param& p, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
{
if( auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue_mut(*e, u, cb);
+ return visit_mir_lvalue_raw_mut(*e, u, cb);
}
else
{
@@ -358,7 +387,7 @@ namespace {
{
if( const auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue(*e, u, cb);
+ return visit_mir_lvalue_raw(*e, u, cb);
}
else
{
@@ -371,7 +400,7 @@ namespace {
bool rv = false;
TU_MATCHA( (rval), (se),
(Use,
- rv |= visit_mir_lvalue_mut(se, ValUsage::Move, cb); // Can move
+ rv |= visit_mir_lvalue_raw_mut(se, ValUsage::Move, cb); // Can move
),
(Constant,
),
@@ -379,23 +408,23 @@ namespace {
rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Has to be Read
),
(Borrow,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Borrow, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Borrow, cb);
),
(Cast,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Also has to be read
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Also has to be read
),
(BinOp,
rv |= visit_mir_lvalue_mut(se.val_l, ValUsage::Read, cb); // Same
rv |= visit_mir_lvalue_mut(se.val_r, ValUsage::Read, cb);
),
(UniOp,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(DstMeta,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Reads
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Reads
),
(DstPtr,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(MakeDst,
rv |= visit_mir_lvalue_mut(se.ptr_val, ValUsage::Move, cb);
@@ -430,19 +459,19 @@ namespace {
TU_MATCHA( (stmt), (e),
(Assign,
rv |= visit_mir_lvalues_mut(e.src, cb);
- rv |= visit_mir_lvalue_mut(e.dst, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.dst, ValUsage::Write, cb);
),
(Asm,
for(auto& v : e.inputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Read, cb);
for(auto& v : e.outputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Write, cb);
),
(SetDropFlag,
),
(Drop,
// Well, it mutates...
- rv |= visit_mir_lvalue_mut(e.slot, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.slot, ValUsage::Write, cb);
),
(ScopeEnd,
)
@@ -454,8 +483,9 @@ namespace {
return visit_mir_lvalues_mut(const_cast<::MIR::Statement&>(stmt), [&](auto& lv, auto im){ return cb(lv, im); });
}
- void visit_mir_lvalues_mut(::MIR::Terminator& term, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues_mut(::MIR::Terminator& term, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
{
+ bool rv = false;
TU_MATCHA( (term), (e),
(Incomplete,
),
@@ -468,27 +498,28 @@ namespace {
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.cond, ValUsage::Read, cb);
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(Call,
if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.fcn.as_Value(), ValUsage::Read, cb);
}
for(auto& v : e.args)
- visit_mir_lvalue_mut(v, ValUsage::Move, cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_mut(v, ValUsage::Move, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.ret_val, ValUsage::Write, cb);
)
)
+ return rv;
}
- void visit_mir_lvalues(const ::MIR::Terminator& term, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues(const ::MIR::Terminator& term, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
{
- visit_mir_lvalues_mut(const_cast<::MIR::Terminator&>(term), [&](auto& lv, auto im){ return cb(lv, im); });
+ return visit_mir_lvalues_mut(const_cast<::MIR::Terminator&>(term), [&](auto& lv, auto im){ return cb(lv, im); });
}
void visit_mir_lvalues_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
@@ -733,32 +764,6 @@ namespace {
void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, const ::MIR::BasicBlock&)> cb) {
visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); });
}
-
- bool statement_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& lv)
- {
- return visit_mir_lvalues(stmt, [&](const auto& v, auto vu) {
- if( v == lv ) {
- return vu != ValUsage::Read;
- }
- return false;
- });
- }
- bool terminator_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& lv)
- {
- if( const auto* e = term.opt_Call() )
- {
- return visit_mir_lvalue(e->ret_val, ValUsage::Write, [&](const auto& v, auto vu) {
- if( v == lv ) {
- return vu != ValUsage::Read;
- }
- return false;
- });
- }
- else
- {
- return false;
- }
- }
}
@@ -859,12 +864,31 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
{
bool inline_happened = false;
TRACE_FUNCTION_FR("", inline_happened);
+ struct InlineEvent {
+ ::HIR::Path path;
+ ::std::vector<size_t> bb_list;
+ InlineEvent(::HIR::Path p)
+ :path(::std::move(p))
+ {
+ }
+ bool has_bb(size_t i) const {
+ return ::std::find(this->bb_list.begin(), this->bb_list.end(), i) != this->bb_list.end();
+ }
+ void add_range(size_t start, size_t count) {
+ for(size_t j = 0; j < count; j++)
+ {
+ this->bb_list.push_back(start + j);
+ }
+ }
+ };
+ ::std::vector<InlineEvent> inlined_functions;
struct H
{
static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal)
{
// TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents
+ // TODO: Take a monomorph helper so recursion can be detected
if( minimal ) {
return false;
@@ -888,6 +912,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
return false;
// Detect and avoid simple recursion.
// - This won't detect mutual recursion - that also needs prevention.
+ // TODO: This is the pre-monomorph path, but we're comparing with the post-monomorph path
if( blk0_te.fcn.is_Path() && blk0_te.fcn.as_Path() == path )
return false;
return true;
@@ -907,6 +932,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
// Recursion, don't inline.
if( te.fcn.is_Path() && te.fcn.as_Path() == path )
return false;
+ // HACK: Only allow if the wrapped function is an intrinsic
+ // - Works around the TODO about monomorphed paths above
+ if(!te.fcn.is_Intrinsic())
+ return false;
}
}
return true;
@@ -1139,42 +1168,34 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
::MIR::LValue clone_lval(const ::MIR::LValue& src) const
{
- TU_MATCHA( (src), (se),
+ auto wrappers = src.m_wrappers;
+ for(auto& w : wrappers)
+ {
+ if( w.is_Index() ) {
+ w = ::MIR::LValue::Wrapper::new_Index( this->var_base + w.as_Index() );
+ }
+ }
+ TU_MATCHA( (src.m_root), (se),
(Return,
- return this->retval.clone();
+ return this->retval.clone_wrapped( mv$(wrappers) );
),
(Argument,
- const auto& arg = this->te.args.at(se.idx);
- if( this->copy_args[se.idx] != ~0u )
+ const auto& arg = this->te.args.at(se);
+ if( this->copy_args[se] != ~0u )
{
- return ::MIR::LValue::make_Local(this->copy_args[se.idx]);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->copy_args[se]), mv$(wrappers) );
}
else
{
assert( !arg.is_Constant() ); // Should have been handled in the above
- return arg.as_LValue().clone();
+ return arg.as_LValue().clone_wrapped( mv$(wrappers) );
}
),
(Local,
- return ::MIR::LValue::make_Local(this->var_base + se);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->var_base + se), mv$(wrappers) );
),
(Static,
- return this->monomorph( se );
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({ box$(this->clone_lval(*se.val)) });
- ),
- (Field,
- return ::MIR::LValue::make_Field({ box$(this->clone_lval(*se.val)), se.field_index });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(this->clone_lval(*se.val)),
- box$(this->clone_lval(*se.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({ box$(this->clone_lval(*se.val)), se.variant_index });
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(this->monomorph(se)), mv$(wrappers) );
)
)
throw "";
@@ -1189,10 +1210,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
(Bytes, return ::MIR::Constant(ce);),
(StaticString, return ::MIR::Constant(ce);),
(Const,
- return ::MIR::Constant::make_Const({ this->monomorph(ce.p) });
+ return ::MIR::Constant::make_Const({ box$(this->monomorph(*ce.p)) });
),
(ItemAddr,
- return ::MIR::Constant::make_ItemAddr(this->monomorph(ce));
+ return ::MIR::Constant::make_ItemAddr(box$(this->monomorph(*ce)));
)
)
throw "";
@@ -1272,6 +1293,15 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
if( ! te->fcn.is_Path() )
continue ;
const auto& path = te->fcn.as_Path();
+ DEBUG(state << fcn.blocks[i].terminator);
+
+ for(const auto& e : inlined_functions)
+ {
+ if( path == e.path && e.has_bb(i) )
+ {
+ MIR_BUG(state, "Recursive inline of " << path);
+ }
+ }
Cloner cloner { state.sp, state.m_resolve, *te };
const auto* called_mir = get_called_mir(state, list, path, cloner.params);
@@ -1292,12 +1322,11 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
DEBUG("Can't inline " << path);
continue ;
}
- DEBUG(state << fcn.blocks[i].terminator);
TRACE_FUNCTION_F("Inline " << path);
// Allocate a temporary for the return value
{
- cloner.retval = ::MIR::LValue::make_Local( fcn.locals.size() );
+ cloner.retval = ::MIR::LValue::new_Local( fcn.locals.size() );
DEBUG("- Storing return value in " << cloner.retval);
::HIR::TypeRef tmp_ty;
fcn.locals.push_back( state.get_lvalue_type(tmp_ty, te->ret_val).clone() );
@@ -1341,7 +1370,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
{
::HIR::TypeRef tmp;
auto ty = val.is_Constant() ? state.get_const_type(val.as_Constant()) : state.get_lvalue_type(tmp, val.as_LValue()).clone();
- auto lv = ::MIR::LValue::make_Local( static_cast<unsigned>(fcn.locals.size()) );
+ auto lv = ::MIR::LValue::new_Local( static_cast<unsigned>(fcn.locals.size()) );
fcn.locals.push_back( mv$(ty) );
auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) );
auto stmt = ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) });
@@ -1350,6 +1379,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
}
cloner.const_assignments.clear();
+ // Record the inline event
+ for(auto& e : inlined_functions)
+ {
+ if( e.has_bb(i) )
+ {
+ e.add_range(cloner.bb_base, new_blocks.size());
+ }
+ }
+ inlined_functions.push_back(InlineEvent(path.clone()));
+ inlined_functions.back().add_range(cloner.bb_base, new_blocks.size());
+
// Apply
DEBUG("- Append new blocks");
fcn.blocks.reserve( fcn.blocks.size() + new_blocks.size() );
@@ -1359,11 +1399,670 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
}
fcn.blocks[i].terminator = ::MIR::Terminator::make_Goto( cloner.bb_base );
inline_happened = true;
+
+ // TODO: Store the inlined path along with the start and end BBs, and then use that to detect recursive
+ // inlining
+ // - Recursive inlining should be an immediate panic.
}
}
return inline_happened;
}
+namespace {
+ struct StmtRef {
+ unsigned bb_idx;
+ unsigned stmt_idx;
+ StmtRef(): bb_idx(~0u), stmt_idx(0) {}
+ StmtRef(unsigned b, unsigned s): bb_idx(b), stmt_idx(s) {}
+ };
+ ::std::ostream& operator<<(::std::ostream& os, const StmtRef& x) {
+ return os << "BB" << x.bb_idx << "/" << x.stmt_idx;
+ }
+
+ // Iterates the path between two positions, NOT visiting entry specified by `end`
+ enum class IterPathRes {
+ Abort,
+ EarlyTrue,
+ Complete,
+ };
+ IterPathRes iter_path(
+ const ::MIR::Function& fcn, const StmtRef& start, const StmtRef& end,
+ ::std::function<bool(StmtRef, const ::MIR::Statement&)> cb_stmt,
+ ::std::function<bool(StmtRef, const ::MIR::Terminator&)> cb_term
+ )
+ {
+ if( start.bb_idx == end.bb_idx ) {
+ assert(start.stmt_idx <= end.stmt_idx);
+ }
+
+ auto visted_bbs = ::std::set<unsigned>();
+ // Loop while not equal (either not in the right block, or before the statement) to the end point
+ for(auto ref = start; ref.bb_idx != end.bb_idx || ref.stmt_idx < end.stmt_idx; )
+ {
+ const auto& bb = fcn.blocks.at(ref.bb_idx);
+ if( ref.stmt_idx < bb.statements.size() )
+ {
+ DEBUG(ref << " " << bb.statements.at(ref.stmt_idx));
+ if( cb_stmt(ref, bb.statements.at(ref.stmt_idx)) )
+ {
+ return IterPathRes::EarlyTrue;
+ }
+
+ ref.stmt_idx ++;
+ }
+ else
+ {
+ DEBUG(ref << " " << bb.terminator);
+ if( cb_term(ref, bb.terminator) )
+ {
+ return IterPathRes::EarlyTrue;
+ }
+
+ // If this is the end point, break out before checking the terminator for looping
+ if( ref.bb_idx == end.bb_idx )
+ {
+ // ^ don't need to check the statment index, this is the last "statement"
+ break;
+ }
+
+ // If this terminator is a Goto, follow it (tracking for loops)
+ if( const auto* te = bb.terminator.opt_Goto() )
+ {
+ // Possibly loop into the next block
+ if( !visted_bbs.insert(*te).second ) {
+ return IterPathRes::Abort;
+ }
+ ref.stmt_idx = 0;
+ ref.bb_idx = *te;
+ }
+ // If it's a call, check that the target block ends with Diverge, and iterate that in-place
+ // - Then follow the success path as usual
+ else if( const auto* te = bb.terminator.opt_Call() )
+ {
+ // Check the panic arm (should just be a list of destructor calls follwed by a Diverge terminator)
+ const auto& panic_bb = fcn.blocks[te->panic_block];
+ ASSERT_BUG(Span(), panic_bb.terminator.is_Diverge(), "Panic arm of call does not end with Diverge");
+ if( !panic_bb.statements.empty() )
+ {
+ TODO(Span(), "Visit call panic block");
+ }
+ // Possibly loop into the next block
+ if( !visted_bbs.insert(te->ret_block).second ) {
+ return IterPathRes::Abort;
+ }
+ ref.stmt_idx = 0;
+ ref.bb_idx = te->ret_block;
+ }
+ else
+ {
+ return IterPathRes::Abort;
+ }
+ }
+ }
+ return IterPathRes::Complete;
+ }
+
+ ::std::function<bool(const ::MIR::LValue& , ValUsage)> check_invalidates_lvalue_cb(const ::MIR::LValue& val, bool also_read=false)
+ {
+ bool has_index = ::std::any_of(val.m_wrappers.begin(), val.m_wrappers.end(), [](const auto& w){ return w.is_Index(); });
+ // Value is invalidated if it's used with ValUsage::Write or ValUsage::Borrow
+ // - Same applies to any component of the lvalue
+ return [&val,has_index,also_read](const ::MIR::LValue& lv, ValUsage vu) {
+ switch(vu)
+ {
+ case ValUsage::Move: // A move can invalidate
+ // - Ideally this would check if it DOES invalidate
+ case ValUsage::Write:
+ case ValUsage::Borrow:
+ // (Possibly) mutating use, check if it impacts the root or one of the indexes
+ if( lv.m_root == val.m_root ) {
+ return true;
+ }
+ if( has_index && lv.m_root.is_Local() )
+ {
+ for(const auto& w : val.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ if( w.as_Index() == lv.m_root.as_Local() )
+ {
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ case ValUsage::Read:
+ if( also_read )
+ return true;
+ break;
+ }
+ return false;
+ };
+ }
+ bool check_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& val, bool also_read=false)
+ {
+ return visit_mir_lvalues(stmt, check_invalidates_lvalue_cb(val, also_read));
+ }
+ bool check_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& val, bool also_read=false)
+ {
+ return visit_mir_lvalues(term, check_invalidates_lvalue_cb(val, also_read));
+ }
+}
+
+bool MIR_Optimise_DeTemporary_SingleSetAndUse(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+{
+ bool changed = false;
+ TRACE_FUNCTION_FR("", changed);
+
+ // Find all single-use/single-write locals
+ // - IF the usage is a RValue::Use, AND the usage destination is not invalidated between set/use
+ // - Replace initialisation destination with usage destination (delete usage statement)
+ // - IF the source a Use/Constant, AND is not invalidated between set/use
+ // - Replace usage with the original source
+ struct LocalUsage {
+ unsigned n_write;
+ unsigned n_read;
+ unsigned n_borrow;
+ StmtRef set_loc;
+ StmtRef use_loc;
+ LocalUsage():
+ n_write(0),
+ n_read(0),
+ n_borrow(0)
+ {
+ }
+ };
+ auto usage_info = ::std::vector<LocalUsage>(fcn.locals.size());
+ for(const auto& bb : fcn.blocks)
+ {
+ StmtRef cur_loc;
+ auto visit_cb = [&](const ::MIR::LValue& lv, auto vu) {
+ if( !lv.m_wrappers.empty() ) {
+ vu = ValUsage::Read;
+ }
+ for(const auto& w : lv.m_wrappers)
+ {
+ if(w.is_Index())
+ {
+ auto& slot = usage_info[w.as_Index()];
+ slot.n_read += 1;
+ slot.use_loc = cur_loc;
+ //DEBUG(lv << " index use");
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ auto& slot = usage_info[lv.m_root.as_Local()];
+ switch(vu)
+ {
+ case ValUsage::Write:
+ slot.n_write += 1;
+ slot.set_loc = cur_loc;
+ //DEBUG(lv << " set");
+ break;
+ case ValUsage::Move:
+ slot.n_read += 1;
+ slot.use_loc = cur_loc;
+ //DEBUG(lv << " use");
+ break;
+ case ValUsage::Read:
+ case ValUsage::Borrow:
+ slot.n_borrow += 1;
+ //DEBUG(lv << " borrow");
+ break;
+ }
+ }
+ return false;
+ };
+ for(const auto& stmt : bb.statements)
+ {
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), &stmt - &bb.statements.front());
+ //DEBUG(cur_loc << ":" << stmt);
+ visit_mir_lvalues(stmt, visit_cb);
+ }
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), bb.statements.size());
+ //DEBUG(cur_loc << ":" << bb.terminator);
+ visit_mir_lvalues(bb.terminator, visit_cb);
+ }
+
+ for(size_t var_idx = 0; var_idx < fcn.locals.size(); var_idx ++)
+ {
+ const auto& slot = usage_info[var_idx];
+ auto this_var = ::MIR::LValue::new_Local(var_idx);
+ //ASSERT_BUG(Span(), slot.n_write > 0, "Variable " << var_idx << " not written?");
+ if( slot.n_write == 1 && slot.n_read == 1 && slot.n_borrow == 0 )
+ {
+ // Single-use variable, now check how we can eliminate it
+ DEBUG("Single-use: _" << var_idx << " - Set " << slot.set_loc << ", Use " << slot.use_loc);
+
+ auto& use_bb = fcn.blocks[slot.use_loc.bb_idx];
+ auto& set_bb = fcn.blocks[slot.set_loc.bb_idx];
+ // If usage is direct assignment of the original value.
+ // - In this case, we can move the usage upwards
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() && TU_TEST2(use_bb.statements[slot.use_loc.stmt_idx], Assign, .src, Use, == this_var) )
+ {
+ // Move the usage up to original assignment (if destination isn't invalidated)
+ const auto& dst = use_bb.statements[slot.use_loc.stmt_idx].as_Assign().dst;
+
+ // TODO: If the destination slot was ever borrowed mutably, don't move.
+ // - Maybe, if there's a drop skip? (as the drop could be &mut to the target value)
+
+ // - Iterate the path(s) between the two statements to check if the destination would be invalidated
+ // > The iterate function doesn't (yet) support following BB chains, so assume invalidated if over a jump.
+ bool invalidated = IterPathRes::Complete != iter_path(fcn, slot.set_loc, slot.use_loc,
+ [&](auto loc, const auto& stmt)->bool{ return stmt.is_Drop() || check_invalidates_lvalue(stmt, dst, /*also_read=*/true); },
+ [&](auto loc, const auto& term)->bool{ return check_invalidates_lvalue(term, dst, /*also_read=*/true); }
+ );
+ if( !invalidated )
+ {
+ // destination not dependent on any statements between the two, move.
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() )
+ {
+ auto& set_stmt = set_bb.statements[slot.set_loc.stmt_idx];
+ TU_MATCH_HDRA( (set_stmt), {)
+ TU_ARMA(Assign, se) {
+ MIR_ASSERT(state, se.dst == ::MIR::LValue::new_Local(var_idx), "");
+ DEBUG("Move destination " << dst << " from " << use_bb.statements[slot.use_loc.stmt_idx] << " to " << set_stmt);
+ se.dst = dst.clone();
+ use_bb.statements[slot.use_loc.stmt_idx] = ::MIR::Statement();
+ changed = true;
+ }
+ TU_ARMA(Asm, se) {
+ // Initialised from an ASM statement, find the variable in the output parameters
+ }
+ break;
+ default:
+ MIR_BUG(state, "Impossibility: Value set in " << set_stmt);
+ }
+ }
+ else
+ {
+ auto& set_term = set_bb.terminator;
+ MIR_ASSERT(state, set_term.is_Call(), "Impossibility: Value set using non-call");
+ auto& te = set_term.as_Call();
+ DEBUG("Move destination " << dst << " from " << use_bb.statements[slot.use_loc.stmt_idx] << " to " << set_term);
+ te.ret_val = dst.clone();
+ use_bb.statements[slot.use_loc.stmt_idx] = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ else
+ {
+ DEBUG("Destination invalidated");
+ }
+ continue ;
+ }
+ // Can't move up, can we move down?
+ // - If the source is an Assign(Use) then we can move down
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() && TU_TEST1(set_bb.statements[slot.set_loc.stmt_idx], Assign, .src.is_Use()) )
+ {
+ auto& set_stmt = set_bb.statements[slot.set_loc.stmt_idx];
+ const auto& src = set_stmt.as_Assign().src.as_Use();
+
+ // Check if the source of initial assignment is invalidated in the meantime.
+ // - TODO: We don't want to check the set statement, just all others after it
+ bool invalidated = IterPathRes::Complete != iter_path(fcn, slot.set_loc, slot.use_loc,
+ [&](auto loc, const auto& stmt)->bool{ return check_invalidates_lvalue(stmt, src); },
+ [&](auto loc, const auto& term)->bool{ return check_invalidates_lvalue(term, src); }
+ );
+ if( !invalidated )
+ {
+ // Update the usage site and replace.
+ auto replace_cb = [&](::MIR::LValue& slot, ValUsage vu)->bool {
+ if( slot.m_root == this_var.m_root )
+ {
+ if( src.m_wrappers.empty() ) {
+ slot.m_root = src.m_root.clone();
+ }
+ else if( slot.m_wrappers.empty() ) {
+ slot = src.clone();
+ }
+ else {
+ MIR_TODO(state, "Replace inner of " << slot << " with " << src);
+ }
+ return true;
+ }
+ return false;
+ };
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() )
+ {
+ auto& use_stmt = use_bb.statements[slot.use_loc.stmt_idx];
+ DEBUG("Replace " << this_var << " with " << src << " in " << use_stmt);
+ bool found = visit_mir_lvalues_mut(use_stmt, replace_cb);
+ if( !found )
+ {
+ DEBUG("Can't find use of " << this_var << " in " << use_stmt);
+ }
+ else
+ {
+ set_stmt = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ else
+ {
+ auto& use_term = use_bb.terminator;
+ DEBUG("Replace " << this_var << " with " << src << " in " << use_term);
+ bool found = visit_mir_lvalues_mut(use_term, replace_cb);
+ if( !found )
+ {
+ DEBUG("Can't find use of " << this_var << " in " << use_term);
+ }
+ else
+ {
+ set_stmt = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ }
+ else
+ {
+ DEBUG("Source invalidated");
+ }
+ continue;
+ }
+
+ // TODO: If the source is a Borrow and the use is a Deref, then propagate forwards
+ // - This would be a simpler version of a var more compliciated algorithm
+
+ DEBUG("Can't replace:");
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() )
+ {
+ DEBUG("Set: " << set_bb.statements[slot.set_loc.stmt_idx]);
+ }
+ else
+ {
+ DEBUG("Set: " << set_bb.terminator);
+ }
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() )
+ {
+ DEBUG("Use: " << use_bb.statements[slot.use_loc.stmt_idx]);
+ }
+ else
+ {
+ DEBUG("Use: " << use_bb.terminator);
+ }
+ }
+ }
+
+ return changed;
+}
+
+// Remove useless borrows (locals assigned with a borrow, and never used by value)
+// ```
+// _$1 = & _$0;
+// (*_$1).1 = 0x0;
+// ```
+bool MIR_Optimise_DeTemporary_Borrows(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+{
+ bool changed = false;
+#if 1
+ TRACE_FUNCTION_FR("", changed);
+
+ // Find all single-assign borrows that are only ever used via Deref
+ // - Direct drop is ignored for this purpose
+ struct LocalUsage {
+ unsigned n_write;
+ unsigned n_other_read;
+ unsigned n_deref_read;
+ StmtRef set_loc;
+ ::std::vector<StmtRef> drop_locs;
+ LocalUsage():
+ n_write(0),
+ n_other_read(0),
+ n_deref_read(0)
+ {
+ }
+ };
+ auto usage_info = ::std::vector<LocalUsage>(fcn.locals.size());
+ for(const auto& bb : fcn.blocks)
+ {
+ StmtRef cur_loc;
+ auto visit_cb = [&](const ::MIR::LValue& lv, auto vu) {
+ if( lv.m_root.is_Local() )
+ {
+ auto& slot = usage_info[lv.m_root.as_Local()];
+ // NOTE: This pass doesn't care about indexing, as we're looking for values that are borrows (which aren't valid indexes)
+ // > Inner-most wrapper is Deref - it's a deref of this variable
+ if( !lv.m_wrappers.empty() && lv.m_wrappers.front().is_Deref() ) {
+ slot.n_deref_read ++;
+ if( fcn.locals[lv.m_root.as_Local()].m_data.is_Borrow() ) {
+ DEBUG(lv << " deref use " << cur_loc);
+ }
+ }
+ // > Write with no wrappers - Assignment
+ else if( lv.m_wrappers.empty() && vu == ValUsage::Write ) {
+ slot.n_write ++;
+ slot.set_loc = cur_loc;
+ //DEBUG(lv << " set");
+ }
+ // Anything else, count as a read
+ else {
+ slot.n_other_read ++;
+ }
+ }
+ return false;
+ };
+ for(const auto& stmt : bb.statements)
+ {
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), &stmt - &bb.statements.front());
+
+ // If the statement is a drop of a local, then don't count that as a read
+ // - But do record the location of the drop, so it can be deleted later on?
+ if( stmt.is_Drop() )
+ {
+ const auto& drop_lv = stmt.as_Drop().slot;
+ if( drop_lv.m_root.is_Local() && drop_lv.m_wrappers.empty() )
+ {
+ auto& slot = usage_info[drop_lv.m_root.as_Local()];
+ slot.drop_locs.push_back(cur_loc);
+ continue ;
+ }
+ }
+
+ //DEBUG(cur_loc << ":" << stmt);
+ visit_mir_lvalues(stmt, visit_cb);
+ }
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), bb.statements.size());
+ //DEBUG(cur_loc << ":" << bb.terminator);
+ visit_mir_lvalues(bb.terminator, visit_cb);
+ }
+
+ // Look single-write/deref-only locals assigned with `_0 = Borrow`
+ for(size_t var_idx = 0; var_idx < fcn.locals.size(); var_idx ++)
+ {
+ const auto& slot = usage_info[var_idx];
+ auto this_var = ::MIR::LValue::new_Local(var_idx);
+
+ // This rule only applies to single-write variables, with no use other than via derefs
+ if( !(slot.n_write == 1 && slot.n_other_read == 0) )
+ {
+ //DEBUG(this_var << " - Multi-assign, or use-by-value");
+ continue ;
+ }
+ if( slot.n_deref_read == 0 )
+ {
+ //DEBUG(this_var << " - Not used");
+ continue ;
+ }
+
+ // Check that the source was a borrow statement
+ auto& src_bb = fcn.blocks[slot.set_loc.bb_idx];
+ if( !(slot.set_loc.stmt_idx < src_bb.statements.size() && TU_TEST1(src_bb.statements[slot.set_loc.stmt_idx], Assign, .src.is_Borrow())) )
+ {
+ DEBUG(this_var << " - Source is not a borrow op");
+ continue;
+ }
+ const auto& src_lv = src_bb.statements[slot.set_loc.stmt_idx].as_Assign().src.as_Borrow().val;
+ // Check that the borrow isn't too complex
+ // TODO: If there's only one use, then no complexity limit?
+ if( src_lv.m_wrappers.size() >= 2 )
+ {
+ DEBUG(this_var << " - Source is too complex - " << src_lv);
+ continue;
+ }
+ if( slot.n_deref_read > 1 && fcn.locals[var_idx].m_data.as_Borrow().type != ::HIR::BorrowType::Shared )
+ {
+ DEBUG(this_var << " - Multi-use non-shared borrow, too complex to do");
+ continue;
+ }
+ DEBUG(this_var << " - Borrow of " << src_lv << " at " << slot.set_loc << ", used " << slot.n_deref_read << " times (dropped " << slot.drop_locs << ")");
+
+ // Locate usage sites (by walking forwards) and check for invalidation
+ auto cur_loc = slot.set_loc;
+ cur_loc.stmt_idx ++;
+ unsigned num_replaced = 0;
+ auto replace_cb = [&](::MIR::LValue& lv, auto _vu) {
+ if( lv.m_root == this_var.m_root )
+ {
+ ASSERT_BUG(Span(), !lv.m_wrappers.empty(), cur_loc << " " << lv);
+ assert(lv.m_wrappers.front().is_Deref());
+ // Make a LValue reference, then overwrite it
+ {
+ auto lvr = ::MIR::LValue::MRef(lv);
+ while(lvr.wrapper_count() > 1)
+ lvr.try_unwrap();
+ DEBUG(this_var << " " << cur_loc << " - Replace " << lvr << " with " << src_lv << " in " << lv);
+ lvr.replace(src_lv.clone());
+ }
+ DEBUG("= " << lv);
+ assert(lv.m_root != this_var.m_root);
+ assert(num_replaced < slot.n_deref_read);
+ num_replaced += 1;
+ }
+ return false;
+ };
+ for(bool stop = false; !stop; )
+ {
+ auto& cur_bb = fcn.blocks[cur_loc.bb_idx];
+ for(; cur_loc.stmt_idx < cur_bb.statements.size(); cur_loc.stmt_idx ++)
+ {
+ auto& stmt = cur_bb.statements[cur_loc.stmt_idx];
+ DEBUG(cur_loc << " " << stmt);
+ // Replace usage
+ bool invalidates = check_invalidates_lvalue(stmt, src_lv);
+ visit_mir_lvalues_mut(stmt, replace_cb);
+ if( num_replaced == slot.n_deref_read )
+ {
+ stop = true;
+ break;
+ }
+ // Check for invalidation (actual check done before replacement)
+ if( invalidates )
+ {
+ // Invalidated, stop here.
+ DEBUG(this_var << " - Source invalidated @ " << cur_loc << " in " << stmt);
+ stop = true;
+ break;
+ }
+ }
+ if( stop ) {
+ break;
+ }
+ // Replace usage
+ visit_mir_lvalues_mut(cur_bb.terminator, replace_cb);
+ if( num_replaced == slot.n_deref_read )
+ {
+ stop = true;
+ break;
+ }
+ // Check for invalidation
+ if( check_invalidates_lvalue(cur_bb.terminator, src_lv) )
+ {
+ DEBUG(this_var << " - Source invalidated @ " << cur_loc << " in " << cur_bb.terminator);
+ stop = true;
+ break;
+ }
+
+ TU_MATCH_HDRA( (cur_bb.terminator), { )
+ default:
+ stop = true;
+ break;
+ // TODO: History is needed to avoid infinite loops from triggering infinite looping here.
+ //TU_ARMA(Goto, e) {
+ // cur_pos.bb_idx = e;
+ // cur_pos.stmt_idx = 0;
+ // }
+ // NOTE: `Call` can't work in the presense of unwinding, would need to traverse both paths
+ //TU_ARMA(Call, e) {
+ // }
+ }
+ }
+
+ // If the source was an inner deref, update its counts
+ if( src_lv.m_root.is_Local() && !src_lv.m_wrappers.empty() && src_lv.m_wrappers.front().is_Deref() )
+ {
+ usage_info[src_lv.m_root.as_Local()].n_deref_read += num_replaced;
+ if(num_replaced == slot.n_deref_read)
+ {
+ usage_info[src_lv.m_root.as_Local()].n_deref_read -= 1;
+ }
+ }
+
+ // If all usage sites were updated, then remove the original assignment
+ if(num_replaced == slot.n_deref_read)
+ {
+ DEBUG(this_var << " - Erase " << slot.set_loc << " as it is no longer used (" << src_bb.statements[slot.set_loc.stmt_idx] << ")");
+ src_bb.statements[slot.set_loc.stmt_idx] = ::MIR::Statement();
+ for(const auto& drop_loc : slot.drop_locs)
+ {
+ DEBUG(this_var << " - Drop at " << drop_loc);
+ fcn.blocks[drop_loc.bb_idx].statements[drop_loc.stmt_idx] = ::MIR::Statement();
+ }
+ }
+#if 0
+ else if( num_replaced > 0 )
+ {
+ auto src_rval = ::std::move(src_bb.statements[slot.set_loc.stmt_idx].as_Assign().src);
+ src_bb.statements[slot.set_loc.stmt_idx] = ::MIR::Statement();
+ DEBUG(this_var << " - Move " << slot.set_loc << " to after " << cur_loc);
+ // TODO: Move the source borrow up to this point.
+ auto& cur_bb = fcn.blocks[cur_loc.bb_idx];
+ if( cur_loc.stmt_idx >= cur_bb.statements.size() )
+ {
+ auto push_bb_front = [&fcn,&this_var](unsigned b, ::MIR::RValue s){
+ fcn.blocks[b].statements.insert(fcn.blocks[b].statements.begin(), ::MIR::Statement::make_Assign({ this_var.clone(), ::std::move(s) }));
+ // TODO: Update all references to this block?
+ };
+ // Move the borrow to the next block?
+ // - Terminators shouldn't be able to invalidate...
+ TU_MATCH_HDRA( (cur_bb.terminator), { )
+ default:
+ TODO(Span(), "Move borrow to after terminator " << cur_bb.terminator);
+ TU_ARMA(Goto, e) {
+ push_bb_front(e, ::std::move(src_rval));
+ }
+ TU_ARMA(Call, e) {
+ push_bb_front(e.ret_block, src_rval.clone());
+ push_bb_front(e.panic_block, ::std::move(src_rval));
+ }
+ }
+ }
+ else
+ {
+ // If invalidated, then there _shouldn't_ be more to come (borrow rules)
+ TODO(Span(), "Move borrow to after " << cur_loc);
+ }
+ }
+#endif
+ else
+ {
+ // No replacement, keep the source where it is
+ DEBUG(this_var << " - Keep " << slot.set_loc);
+ }
+
+ // Any replacements? Then there was an actionable change
+ if( num_replaced > 0 )
+ {
+ changed = true;
+ }
+ }
+#endif
+
+ return changed;
+}
+
// --------------------------------------------------------------------
// Replaces uses of stack slots with what they were assigned with (when
// possible)
@@ -1373,10 +2072,16 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool changed = false;
TRACE_FUNCTION_FR("", changed);
+ changed |= MIR_Optimise_DeTemporary_SingleSetAndUse(state, fcn);
+ changed |= MIR_Optimise_DeTemporary_Borrows(state, fcn);
+
+
+ // OLD ALGORITHM.
for(unsigned int bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++)
{
auto& bb = fcn.blocks[bb_idx];
::std::map<unsigned,unsigned> local_assignments; // Local number -> statement index
+ // TODO: Keep track of what variables would invalidate a local (and compound on assignment)
::std::vector<unsigned> statements_to_remove; // List of statements that have to be removed
// ----- Helper closures -----
@@ -1388,7 +2093,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& src_rvalue = bb.statements[it->second].as_Assign().src;
// Destination invalidated?
- if( lv.is_Local() && it->first == lv.as_Local() )
+ if( lv.m_root.is_Local() && it->first == lv.m_root.as_Local() )
{
switch(vu)
{
@@ -1409,8 +2114,9 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
case ValUsage::Borrow: // Borrows are annoying, assume they invalidate anything used
case ValUsage::Write: // Mutated? It's invalidated
case ValUsage::Move: // Moved? Now invalid
- visit_mir_lvalues(src_rvalue, [&](const auto& s_lv, auto /*s_vu*/) {
- if( s_lv == lv )
+ visit_mir_lvalues(src_rvalue, [&](const ::MIR::LValue& s_lv, auto s_vu) {
+ //DEBUG(" " << s_lv << " ?= " << lv);
+ if( s_lv.m_root == lv.m_root )
{
DEBUG(state << "> Invalidates source of Local(" << it->first << ") - " << src_rvalue);
invalidated = true;
@@ -1444,39 +2150,37 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// > For now, don't do the replacement if it would delete the assignment UNLESS it's directly being used)
// 2. Search for replacements
- bool top_level = true;
- visit_mir_lvalue_mut(top_lv, top_usage, [&](auto& ilv, auto /*i_usage*/) {
- if( ilv.is_Local() )
+ if( top_lv.m_root.is_Local() )
+ {
+ bool top_level = top_lv.m_wrappers.empty();
+ auto ilv = ::MIR::LValue::new_Local(top_lv.m_root.as_Local());
+ auto it = local_assignments.find(top_lv.m_root.as_Local());
+ if( it != local_assignments.end() )
{
- auto it = local_assignments.find(ilv.as_Local());
- if( it != local_assignments.end() )
+ const auto& new_val = bb.statements[it->second].as_Assign().src.as_Use();
+ // - Copy? All is good.
+ if( state.lvalue_is_copy(ilv) )
{
- // - Copy? All is good.
- if( state.lvalue_is_copy(ilv) )
- {
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << ilv);
- }
- // - Top-level (directly used) also good.
- else if( top_level && top_usage == ValUsage::Move )
- {
- // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << ilv);
- statements_to_remove.push_back( it->second );
- local_assignments.erase(it);
- }
- // - Otherwise, remove the record.
- else
- {
- DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
- local_assignments.erase(it);
- }
+ top_lv = new_val.clone_wrapped(top_lv.m_wrappers.begin(), top_lv.m_wrappers.end());
+ DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << new_val);
+ }
+ // - Top-level (directly used) also good.
+ else if( top_level && top_usage == ValUsage::Move )
+ {
+ // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
+ top_lv = new_val.clone();
+ DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << new_val);
+ statements_to_remove.push_back( it->second );
+ local_assignments.erase(it);
+ }
+ // - Otherwise, remove the record.
+ else
+ {
+ DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
+ local_assignments.erase(it);
}
}
- top_level = false;
- return false;
- });
+ }
// Return true to prevent recursion
return true;
};
@@ -1503,12 +2207,16 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// - Check if this is a new assignment
if( stmt.is_Assign() && stmt.as_Assign().dst.is_Local() && stmt.as_Assign().src.is_Use() )
{
- if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) {
- return lv == stmt.as_Assign().dst;
- }) )
+ const auto& dst_lv = stmt.as_Assign().dst;
+ const auto& src_lv = stmt.as_Assign().src.as_Use();
+ if( visit_mir_lvalues_inner(src_lv, ValUsage::Read, [&](const auto& lv, auto) { return lv.m_root == dst_lv.m_root; }) )
{
DEBUG(state << "> Don't record, self-referrential");
}
+ else if( ::std::any_of(src_lv.m_wrappers.begin(), src_lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
+ {
+ DEBUG(state << "> Don't record, dereference");
+ }
else
{
local_assignments.insert(::std::make_pair( stmt.as_Assign().dst.as_Local(), stmt_idx ));
@@ -1680,12 +2388,13 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
{
DEBUG("Replacing temporaries using {" << replacements << "}");
visit_mir_lvalues_mut(state, fcn, [&](auto& lv, auto ) {
- if( auto* ve = lv.opt_Local() ) {
- auto it = replacements.find(*ve);
+ if( lv.m_root.is_Local() )
+ {
+ auto it = replacements.find(lv.m_root.as_Local());
if( it != replacements.end() )
{
MIR_DEBUG(state, lv << " => Local(" << it->second << ")");
- *ve = it->second;
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second);
return true;
}
}
@@ -1948,7 +2657,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
if( stmt_idx == bb.statements.size() )
{
DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
- if( terminator_invalidates_lvalue(bb.terminator, slot_lvalue) ) {
+ if( check_invalidates_lvalue(bb.terminator, slot_lvalue) ) {
return nullptr;
}
continue ;
@@ -1982,13 +2691,13 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
if(stmt_idx == bb.statements.size())
{
DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
- if( terminator_invalidates_lvalue(bb.terminator, src_lval) ) {
+ if( check_invalidates_lvalue(bb.terminator, src_lval) ) {
// Invalidated: Return.
return nullptr;
}
continue ;
}
- if( statement_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) {
+ if( check_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) {
// Invalidated: Return.
return nullptr;
}
@@ -2002,7 +2711,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
}
// Check if the slot is invalidated (mutated)
- if( statement_invalidates_lvalue(stmt, slot_lvalue) ) {
+ if( check_invalidates_lvalue(stmt, slot_lvalue) ) {
return nullptr;
}
}
@@ -2021,33 +2730,34 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
state.set_cur_stmt(bb_idx, i);
DEBUG(state << block.statements[i]);
visit_mir_lvalues_mut(block.statements[i], [&](::MIR::LValue& lv, auto vu) {
- if(const auto* e = lv.opt_Field())
+ if(vu == ValUsage::Read && lv.m_wrappers.size() > 1 && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local())
{
- if(vu == ValUsage::Read && e->val->is_Local() ) {
- // TODO: This value _must_ be Copy for this optimisation to work.
- // - OR, it has to somehow invalidate the original tuple
- DEBUG(state << "Locating origin of " << lv);
- ::HIR::TypeRef tmp;
- if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, *e->val)) )
+ auto field_index = lv.m_wrappers.front().as_Field();
+ auto inner_lv = ::MIR::LValue::new_Local(lv.m_root.as_Local());
+ auto outer_lv = ::MIR::LValue::new_Field(inner_lv.clone(), field_index);
+ // TODO: This value _must_ be Copy for this optimisation to work.
+ // - OR, it has to somehow invalidate the original tuple
+ DEBUG(state << "Locating origin of " << lv);
+ ::HIR::TypeRef tmp;
+ if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, inner_lv)) )
+ {
+ DEBUG(state << "- not Copy, can't optimise");
+ return false;
+ }
+ const auto* source_lvalue = get_field(inner_lv, field_index, bb_idx, i);
+ if( source_lvalue )
+ {
+ if( outer_lv != *source_lvalue )
{
- DEBUG(state << "- not Copy, can't optimise");
- return false;
+ DEBUG(state << "Source is " << *source_lvalue);
+ lv = source_lvalue->clone_wrapped( lv.m_wrappers.begin() + 1, lv.m_wrappers.end() );
+ change_happend = true;
}
- const auto* source_lvalue = get_field(*e->val, e->field_index, bb_idx, i);
- if( source_lvalue )
+ else
{
- if( lv != *source_lvalue )
- {
- DEBUG(state << "Source is " << *source_lvalue);
- lv = source_lvalue->clone();
- change_happend = true;
- }
- else
- {
- DEBUG(state << "No change");
- }
- return false;
+ DEBUG(state << "No change");
}
+ return false;
}
}
return false;
@@ -2148,6 +2858,23 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block);
changed = true;
}
+ else if( tef.name == "needs_drop" )
+ {
+ // Returns `true` if the actual type given as `T` requires drop glue;
+ // returns `false` if the actual type provided for `T` implements `Copy`. (Either otherwise)
+ // NOTE: libarena assumes that this returns `true` iff T doesn't require drop glue.
+ const auto& ty = tef.params.m_types.at(0);
+ // - Only expand at this stage if there's no generics, and no unbound paths
+ if( !visit_ty_with(ty, [](const ::HIR::TypeRef& ty)->bool{
+ return ty.m_data.is_Generic() || TU_TEST1(ty.m_data, Path, .binding.is_Unbound());
+ }) )
+ {
+ bool needs_drop = state.m_resolve.type_needs_drop_glue(state.sp, ty);
+ bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), ::MIR::RValue::make_Constant(::MIR::Constant::make_Bool({needs_drop})) }));
+ bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block);
+ changed = true;
+ }
+ }
else
{
// Ignore any other intrinsics
@@ -2170,13 +2897,42 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
::std::map< ::MIR::LValue, unsigned > known_values_var;
::std::map< unsigned, bool > known_drop_flags;
+ auto check_lv = [&](const ::MIR::LValue& lv)->::MIR::Constant {
+ auto it = known_values.find(lv);
+ if( it != known_values.end() )
+ {
+ DEBUG(state << "Value " << lv << " known to be" << it->second);
+ return it->second.clone();
+ }
+
+ // TODO: If the inner of the value is known,
+ // AND all indexes are known - expand
+ //if( !lv.m_wrappers.empty() )
+ //{
+ // it = known_values.find(lv.m_root);
+ // if( it != known_values.end() )
+ // {
+ // // TODO: Use HIR::Literal instead so composites can be handled.
+ // for(const auto& w : lv.m_wrappers)
+ // {
+ // }
+ // }
+ //}
+
+ // Not a known value, and not a known composite
+ // - Use a nullptr ItemAddr to indicate this
+ return ::MIR::Constant::make_ItemAddr({});
+ };
auto check_param = [&](::MIR::Param& p) {
if(const auto* pe = p.opt_LValue()) {
- auto it = known_values.find(*pe);
- if( it != known_values.end() )
+ auto nv = check_lv(*pe);
+ if( nv.is_ItemAddr() && !nv.as_ItemAddr() )
+ {
+ // ItemAddr with a nullptr inner means "no expansion"
+ }
+ else
{
- DEBUG(state << "Value " << *pe << " known to be " << it->second);
- p = it->second.clone();
+ p = mv$(nv);
}
}
};
@@ -2193,11 +2949,14 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
TU_MATCHA( (e->src), (se),
(Use,
- auto it = known_values.find(se);
- if( it != known_values.end() )
+ auto nv = check_lv(se);
+ if( nv.is_ItemAddr() && !nv.as_ItemAddr() )
{
- DEBUG(state << "Value " << se << " known to be" << it->second);
- e->src = it->second.clone();
+ // ItemAddr with a nullptr inner means "no expansion"
+ }
+ else
+ {
+ e->src = ::MIR::RValue::make_Constant(mv$(nv));
}
),
(Constant,
@@ -2219,75 +2978,157 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& val_l = se.val_l.as_Constant();
const auto& val_r = se.val_r.as_Constant();
- ::MIR::Constant new_value;
- bool replace = false;
- switch(se.op)
+ if( val_l.is_Const() || val_r.is_Const() )
{
- case ::MIR::eBinOp::EQ:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
+ }
+ else
+ {
+ struct H {
+ static int64_t truncate_s(::HIR::CoreType ct, int64_t v) {
+ return v;
+ }
+ static uint64_t truncate_u(::HIR::CoreType ct, uint64_t v) {
+ switch(ct)
+ {
+ case ::HIR::CoreType::U8: return v & 0xFF;
+ case ::HIR::CoreType::U16: return v & 0xFFFF;
+ case ::HIR::CoreType::U32: return v & 0xFFFFFFFF;
+ case ::HIR::CoreType::U64: return v;
+ case ::HIR::CoreType::U128: return v;
+ case ::HIR::CoreType::Usize: return v;
+ case ::HIR::CoreType::Char:
+ //MIR_BUG(state, "Invalid use of operator on char");
+ break;
+ default:
+ // Invalid type for Uint literal
+ break;
+ }
+ return v;
+ }
+ };
+ ::MIR::Constant new_value;
+ switch(se.op)
{
- replace = true;
+ case ::MIR::eBinOp::EQ:
new_value = ::MIR::Constant::make_Bool({val_l == val_r});
- }
- break;
- case ::MIR::eBinOp::NE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::NE:
new_value = ::MIR::Constant::make_Bool({val_l != val_r});
- }
- break;
- case ::MIR::eBinOp::LT:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::LT:
new_value = ::MIR::Constant::make_Bool({val_l < val_r});
- }
- break;
- case ::MIR::eBinOp::LE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::LE:
new_value = ::MIR::Constant::make_Bool({val_l <= val_r});
- }
- break;
- case ::MIR::eBinOp::GT:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::GT:
new_value = ::MIR::Constant::make_Bool({val_l > val_r});
- }
- break;
- case ::MIR::eBinOp::GE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::GE:
new_value = ::MIR::Constant::make_Bool({val_l >= val_r});
+ break;
+
+ case ::MIR::eBinOp::ADD:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v + re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v + re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::SUB:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::SUB - " << val_l << " + " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::SUB - " << val_l << " - " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v - re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::SUB - " << val_l << " - " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v - re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::MUL:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v * re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v * re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::DIV:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v / re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v / re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::MOD:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v % re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v % re.v), le.t });
+ }
+ }}
+ break;
+ // TODO: Other binary operations
+ // Could emit a TODO?
+ default:
+ break;
}
- break;
- // TODO: Other binary operations
- // Could emit a TODO?
- default:
- break;
- }
- if( replace )
- {
- DEBUG(state << " " << e->src << " = " << new_value);
- e->src = mv$(new_value);
- changed = true;
+ if( new_value != ::MIR::Constant() )
+ {
+ DEBUG(state << " " << e->src << " = " << new_value);
+ e->src = mv$(new_value);
+ changed = true;
+ }
}
}
),
@@ -2305,6 +3146,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
TU_MATCHA( (val), (ve),
(Uint,
auto val = ve.v;
+ replace = true;
switch(ve.t)
{
case ::HIR::CoreType::U8: val = (~val) & 0xFF; break;
@@ -2315,17 +3157,17 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
val = ~val;
break;
case ::HIR::CoreType::U128:
- val = ~val;
+ replace = false;
break;
case ::HIR::CoreType::Char:
MIR_BUG(state, "Invalid use of ! on char");
break;
default:
// Invalid type for Uint literal
+ replace = false;
break;
}
new_value = ::MIR::Constant::make_Uint({ val, ve.t });
- replace = true;
),
(Int,
// Is ! valid on Int?
@@ -2588,7 +3430,10 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// --------------------------------------------------------------------
// Split `var = Tuple(...,)` into `varN = ...` if the tuple isn't used by
-// value.
+// value (nor borrowed).
+//
+// NOTE: The "nor borrowed" rule is needed to avoid issues when the first element of a tuple
+// is used as a proxy for the entire tuple.
// --------------------------------------------------------------------
bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
@@ -2642,6 +3487,18 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
auto it = potentials.find(lv.as_Local());
if( it != potentials.end() )
{
+ DEBUG(lv << " invalidated due to root usage");
+ potentials.erase(it);
+ }
+ }
+ // If the variable is borrowed (even via wrappers)
+ // TODO: Restrict this to when the borrow is just via field accesses
+ if( lv.m_root.is_Local() && vu == ValUsage::Borrow )
+ {
+ auto it = potentials.find(lv.m_root.as_Local());
+ if( it != potentials.end() )
+ {
+ DEBUG(lv << " invalidate due to any borrow");
potentials.erase(it);
}
}
@@ -2689,15 +3546,17 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(auto& blk : fcn.blocks)
{
auto cb = [&](auto& lv, auto _vu) {
- if(lv.is_Field() && lv.as_Field().val->is_Local())
+ if( !lv.m_wrappers.empty() && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local() )
{
- auto fld_idx = lv.as_Field().field_index;
- auto it = replacements.find( lv.as_Field().val->as_Local() );
+ auto fld_idx = lv.m_wrappers.front().as_Field();
+ auto it = replacements.find( lv.m_root.as_Local() );
if( it != replacements.end() )
{
MIR_ASSERT(state, fld_idx < it->second.size(), "Tuple field index out of range");
DEBUG(state << "Replace " << lv << " with Local(" << it->second.at(fld_idx) << ")");
- lv = ::MIR::LValue::make_Local(it->second.at(fld_idx));
+
+ lv.m_wrappers.erase( lv.m_wrappers.begin() );
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second.at(fld_idx));
}
}
return false;
@@ -2719,7 +3578,7 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(size_t i = 0; i < vals.size(); i ++)
{
- auto lv = ::MIR::LValue::make_Local(rit->second[i]);
+ auto lv = ::MIR::LValue::new_Local(rit->second[i]);
auto rv = vals[i].is_LValue()
? ::MIR::RValue(::std::move( vals[i].as_LValue() ))
: ::MIR::RValue(::std::move( vals[i].as_Constant() ))
@@ -2764,13 +3623,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
::std::vector<ValUse> local_uses;
void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) {
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- auto& vu = local_uses[e];
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() ){
+ //local_uses[w.as_Index()].read += 1;
+ local_uses[w.as_Index()].borrow += 1;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ auto& vu = local_uses[lv.m_root.as_Local()];
switch(ut)
{
case ValUsage::Move:
@@ -2778,23 +3640,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
case ValUsage::Write: vu.write += 1; break;
case ValUsage::Borrow: vu.borrow += 1; break;
}
- ),
- (Static,
- ),
- (Field,
- use_lvalue(*e.val, ut);
- ),
- (Deref,
- use_lvalue(*e.val, ut);
- ),
- (Index,
- use_lvalue(*e.val, ut);
- use_lvalue(*e.idx, ValUsage::Read);
- ),
- (Downcast,
- use_lvalue(*e.val, ut);
- )
- )
+ }
}
} val_uses = {
::std::vector<ValUse>(fcn.locals.size())
@@ -2810,7 +3656,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// > Replace usage with the inner of the original `Use`
{
// 1. Assignments (forward propagate)
- ::std::map< ::MIR::LValue, ::MIR::RValue> replacements;
+ //::std::map< ::MIR::LValue::CRef, ::MIR::RValue> replacements;
+ ::std::vector< ::std::pair<::MIR::LValue, ::MIR::RValue> > replacements;
+ auto replacements_find = [&replacements](const ::MIR::LValue::CRef& lv) {
+ return ::std::find_if(replacements.begin(), replacements.end(), [&](const auto& e) { return lv == e.first; });
+ };
for(const auto& block : fcn.blocks)
{
if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
@@ -2818,16 +3668,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(unsigned int stmt_idx = 0; stmt_idx < block.statements.size(); stmt_idx ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), stmt_idx);
const auto& stmt = block.statements[stmt_idx];
+ DEBUG(state << stmt);
// > Assignment
if( ! stmt.is_Assign() )
continue ;
const auto& e = stmt.as_Assign();
// > Of a temporary from with a RValue::Use
- if( const auto* de = e.dst.opt_Local() )
+ if( e.dst.is_Local() )
{
- const auto& vu = val_uses.local_uses[*de];
- DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
+ const auto& vu = val_uses.local_uses[e.dst.as_Local()];
+ DEBUG(" - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
// TODO: Allow write many?
// > Where the variable is written once and read once
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
@@ -2837,38 +3689,33 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
continue ;
}
- DEBUG(e.dst << " = " << e.src);
if( e.src.is_Use() )
{
// Keep the complexity down
const auto* srcp = &e.src.as_Use();
- while( srcp->is_Field() )
- srcp = &*srcp->as_Field().val;
- if( !srcp->is_Local() )
+ if( ::std::any_of(srcp->m_wrappers.begin(), srcp->m_wrappers.end(), [](auto& w) { return !w.is_Field(); }) )
+ continue ;
+ if( !srcp->m_root.is_Local() )
continue ;
- if( replacements.find(*srcp) != replacements.end() )
+ if( replacements_find(*srcp) != replacements.end() )
{
DEBUG("> Can't replace, source has pending replacement");
continue;
}
}
- // TODO: Allow any rvalue, but that currently breaks due to chaining
- //else if( e.src.is_Borrow() )
- //{
- //}
else
{
continue ;
}
bool src_is_lvalue = e.src.is_Use();
+ DEBUG("- Locate usage");
- auto is_lvalue_usage = [&](const auto& lv, auto ){ return lv == e.dst; };
-
- // Returns `true` if the passed lvalue is used as a part of the source
- auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalues(e.src, [&](const auto& slv, auto ) { return lv == slv; });
+ auto is_lvalue_usage = [&](const auto& lv, auto ){
+ return lv.m_root == e.dst.m_root;
+ //return lv == e.dst;
};
+
// Eligable for replacement
// Find where this value is used
// - Stop on a conditional block terminator
@@ -2877,8 +3724,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
bool found = false;
for(unsigned int si2 = stmt_idx+1; si2 < block.statements.size(); si2 ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), si2);
const auto& stmt2 = block.statements[si2];
- DEBUG("[find usage] " << stmt2);
+ DEBUG(state << "[find usage] " << stmt2);
+
+ // Check for invalidation (done first, to avoid cases where the source is moved into a struct)
+ if( check_invalidates_lvalue(stmt2, e.src.as_Use()) ) {
+ stop = true;
+ break;
+ }
// Usage found.
if( visit_mir_lvalues(stmt2, is_lvalue_usage) )
@@ -2899,18 +3753,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
stop = true;
break;
}
-
- // Determine if source is mutated.
- // > Assume that any mutating access of the root value counts (over-cautious)
- if( visit_mir_lvalues(stmt2, [&](const auto& lv, auto vu){ return /*vu == ValUsage::Write &&*/ is_lvalue_in_val(lv); }) )
- {
- stop = true;
- break;
- }
}
if( !stop )
{
- DEBUG("[find usage] " << block.terminator);
+ state.set_cur_stmt_term(&block - &fcn.blocks.front());
+ DEBUG(state << "[find usage] " << block.terminator);
+ if( src_is_lvalue )
+ {
+ visit_mir_lvalues(block.terminator, [&](const auto& lv, auto vu) {
+ found |= is_lvalue_usage(lv, vu);
+ return found;
+ });
+ }
TU_MATCHA( (block.terminator), (e),
(Incomplete,
),
@@ -2924,29 +3778,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
(Panic,
),
(If,
- if( src_is_lvalue && visit_mir_lvalue(e.cond, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Switch,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(SwitchValue,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Call,
- if( e.fcn.is_Value() )
- if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, is_lvalue_usage) )
- found = true;
- for(const auto& v : e.args)
- {
- if( src_is_lvalue && visit_mir_lvalue(v, ValUsage::Read, is_lvalue_usage) )
- found = true;
- }
stop = true;
)
)
@@ -2954,8 +3794,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// Schedule a replacement in a future pass
if( found )
{
- DEBUG("> Replace " << e.dst << " with " << e.src.as_Use());
- replacements.insert( ::std::make_pair(e.dst.clone(), e.src.clone()) );
+ DEBUG("> Schedule replace " << e.dst << " with " << e.src.as_Use());
+ replacements.push_back( ::std::make_pair(e.dst.clone(), e.src.clone()) );
}
else
{
@@ -2964,21 +3804,26 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
} // for(stmt : block.statements)
}
+ DEBUG("replacements = " << replacements);
+
// Apply replacements within replacements
for(;;)
{
unsigned int inner_replaced_count = 0;
for(auto& r : replacements)
{
- visit_mir_lvalues_mut(r.second, [&](auto& lv, auto vu) {
+ visit_mir_lvalues_mut(r.second, [&](::MIR::LValue& lv, auto vu) {
if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- auto it = replacements.find(lv);
- if( it != replacements.end() && it->second.is_Use() )
- {
- lv = it->second.as_Use().clone();
- inner_replaced_count ++;
- }
+ visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lvr, auto vu) {
+ auto it = replacements_find(lvr);
+ if( it != replacements.end() && it->second.is_Use() )
+ {
+ lvr.replace( it->second.as_Use().clone() );
+ inner_replaced_count ++;
+ }
+ return false;
+ });
}
return false;
});
@@ -2986,26 +3831,30 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( inner_replaced_count == 0 )
break;
}
+ DEBUG("replacements = " << replacements);
// Apply replacements
unsigned int replaced = 0;
while( replaced < replacements.size() )
{
auto old_replaced = replaced;
- auto cb = [&](auto& lv, auto vu){
- if( vu == ValUsage::Read || vu == ValUsage::Move )
- {
- auto it = replacements.find(lv);
- if( it != replacements.end() )
+ auto cb = [&](::MIR::LValue& lv, auto vu){
+ return visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lv, auto vu) {
+ if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << lv << " fired twice");
- MIR_ASSERT(state, it->second.is_Use(), "Replacing a lvalue with a rvalue - " << lv << " with " << it->second);
- auto rval = ::std::move(it->second);
- lv = ::std::move(rval.as_Use());
- replaced += 1;
+ auto it = replacements_find(lv);
+ if( it != replacements.end() )
+ {
+ MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << lv << " fired twice");
+ MIR_ASSERT(state, it->second.is_Use(), "Replacing a lvalue with a rvalue - " << lv << " with " << it->second);
+ auto rval = ::std::move(it->second);
+ DEBUG("> Do replace " << lv << " => " << rval);
+ lv.replace( ::std::move(rval.as_Use()) );
+ replaced += 1;
+ }
}
- }
- return false;
+ return false;
+ });
};
for(unsigned int block_idx = 0; block_idx < fcn.blocks.size(); block_idx ++)
{
@@ -3015,10 +3864,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(auto& stmt : block.statements)
{
state.set_cur_stmt(block_idx, (&stmt - &block.statements.front()));
+ DEBUG(state << stmt);
+#if 0
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() )
{
auto& e = stmt.as_Assign();
- auto it = replacements.find(e.src.as_Use());
+ auto it = replacements_find(e.src.as_Use());
if( it != replacements.end() )
{
MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << it->first << " fired twice");
@@ -3027,6 +3878,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
}
else
+#endif
{
visit_mir_lvalues_mut(stmt, cb);
}
@@ -3043,8 +3895,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
state.set_cur_stmt(&block - &fcn.blocks.front(), (it - block.statements.begin()));
// If the statement was an assign of a replaced temporary, remove it.
- if( it->is_Assign() && replacements.count( it->as_Assign().dst ) > 0 )
+ auto it2 = replacements.end();
+ if( it->is_Assign() && (it2 = replacements_find(it->as_Assign().dst)) != replacements.end() ) {
+ DEBUG(state << "Delete " << *it);
it = block.statements.erase(it);
+ }
else {
MIR_ASSERT(state, !( it->is_Assign() && it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD ), "");
++it;
@@ -3066,8 +3921,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD )
continue ;
auto& to_replace_lval = it->as_Assign().dst;
- if( const auto* e = to_replace_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( to_replace_lval.is_Local() ){
+ const auto& vu = val_uses.local_uses[to_replace_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
continue ;
}
@@ -3091,8 +3946,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// `... = Use(to_replace_lval)`
// TODO: Ensure that the target isn't borrowed.
- if( const auto* e = new_dst_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( new_dst_lval.is_Local() ) {
+ const auto& vu = val_uses.local_uses[new_dst_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
break ;
}
@@ -3109,7 +3964,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
// Closure returns `true` if the passed lvalue is a component of `new_dst_lval`
auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalue(new_dst_lval, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ // Don't care about indexing?
+ return lv.m_root == new_dst_lval.m_root;
};
if( visit_mir_lvalues(*it3, [&](const auto& lv, auto ){ return is_lvalue_in_val(lv); }) )
{
@@ -3159,7 +4015,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
const ::MIR::LValue* new_dst = nullptr;
auto& blk2 = fcn.blocks.at(e.ret_block);
for(const auto& stmt : blk2.statements)
- {
+ {
// Find `RValue::Use( this_lvalue )`
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val ) {
new_dst = &stmt.as_Assign().dst;
@@ -3170,21 +4026,36 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// Ensure that the new destination value isn't used before assignment
if( new_dst )
{
- auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv) {
- return visit_mir_lvalue(*new_dst, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv)->bool {
+ // Returns true if the two lvalues share a common root
+ // TODO: Could restrict based on the presence of deref/field accesses?
+ // If `lv` is a local AND matches the index in `new_dst`, check for indexing
+ if( lv.is_Local() )
+ {
+ for(const auto& w : new_dst->m_wrappers)
+ {
+ if( w.is_Index() && w.as_Index() == lv.as_Local() )
+ {
+ return true;
+ }
+ }
+ }
+ return lv.m_root == new_dst->m_root;
};
for(auto it = blk2.statements.begin(); it != blk2.statements.end(); ++ it)
{
+ state.set_cur_stmt(&blk2 - &fcn.blocks.front(), it - blk2.statements.begin());
const auto& stmt = *it;
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val )
{
- DEBUG("- Replace function return " << e.ret_val << " with " << *new_dst);
+ DEBUG(state << "- Replace function return " << e.ret_val << " with " << *new_dst);
e.ret_val = new_dst->clone();
+ // TODO: Invalidate the entry, instead of deleting?
it = blk2.statements.erase(it);
replacement_happend = true;
break;
}
- if( visit_mir_lvalues(stmt, [&](const auto& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
+ if( visit_mir_lvalues(stmt, [&](const MIR::LValue& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
{
break;
}
@@ -3218,17 +4089,14 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
// Remove assignments of locals that are never read
- TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de),
- (
- ),
- (Local,
- const auto& vu = val_uses.local_uses[de];
+ if( se->dst.is_Local() )
+ {
+ const auto& vu = val_uses.local_uses[se->dst.as_Local()];
if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) {
DEBUG(state << se->dst << " only written, removing write");
it = block.statements.erase(it)-1;
}
- )
- )
+ }
}
}
// NOTE: Calls can write values, but they also have side-effects
@@ -3356,9 +4224,12 @@ bool MIR_Optimise_DeadAssignments(::MIR::TypeResolve& state, ::MIR::Function& fc
for(const auto& bb : fcn.blocks)
{
auto cb = [&](const ::MIR::LValue& lv, ValUsage vu) {
- if( lv.is_Local() ) {
- read_locals[lv.as_Local()] = true;
+ if( lv.m_root.is_Local() ) {
+ read_locals[lv.m_root.as_Local()] = true;
}
+ for(const auto& w : lv.m_wrappers)
+ if(w.is_Index())
+ read_locals[w.as_Index()] = true;
return false;
};
for(const auto& stmt : bb.statements)
@@ -3425,7 +4296,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
if( it->is_Assign()
&& it->as_Assign().src.is_Borrow()
&& it->as_Assign().src.as_Borrow().val.is_Deref()
- && *it->as_Assign().src.as_Borrow().val.as_Deref().val == it->as_Assign().dst
+ && it->as_Assign().src.as_Borrow().val.clone_unwrapped() == it->as_Assign().dst
)
{
DEBUG(state << "Useless assignment (v = &*v), remove - " << *it);
@@ -3449,7 +4320,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
::std::vector<bool> visited( fcn.blocks.size() );
- visit_blocks(state, fcn, [&visited](auto bb, const auto& _blokc) {
+ visit_blocks(state, fcn, [&visited](auto bb, const auto& /*block*/) {
assert( !visited[bb] );
visited[bb] = true;
});
@@ -3479,12 +4350,19 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
visited[bb] = true;
auto assigned_lval = [&](const ::MIR::LValue& lv) {
- const auto* lvp = &lv;
// TODO: Consume through indexing/field accesses
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
- if(const auto* le = lvp->opt_Local() )
- used_locals[*le] = true;
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Field() ) {
+ }
+ else {
+ return ;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ used_locals[lv.m_root.as_Local()] = true;
+ }
};
for(const auto& stmt : block.statements)
@@ -3558,20 +4436,23 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
auto it = fcn.blocks.begin();
for(unsigned int i = 0; i < visited.size(); i ++)
{
- if( !visited[i] )
- {
- // Delete
- DEBUG("GC bb" << i);
- it = fcn.blocks.erase(it);
- }
- else
+ if( visited[i] )
{
- auto lvalue_cb = [&](auto& lv, auto ) {
- if(auto* e = lv.opt_Local() ) {
- MIR_ASSERT(state, *e < local_rewrite_table.size(), "Variable out of range - " << lv);
+ auto lvalue_cb = [&](::MIR::LValue& lv, auto ) {
+ if( lv.m_root.is_Local() )
+ {
+ auto e = lv.m_root.as_Local();
+ MIR_ASSERT(state, e < local_rewrite_table.size(), "Variable out of range - " << lv);
// If the table entry for this variable is !0, it wasn't marked as used
- MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
- *e = local_rewrite_table.at(*e);
+ MIR_ASSERT(state, local_rewrite_table.at(e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
+ lv.m_root = ::MIR::LValue::Storage::new_Local(local_rewrite_table.at(e) );
+ }
+ for(auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index())
+ {
+ w = ::MIR::LValue::Wrapper::new_Index(local_rewrite_table.at( w.as_Index() ));
+ }
}
return false;
};
@@ -3580,6 +4461,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
{
auto stmt_idx = &stmt - &it->statements.front();
state.set_cur_stmt(i, stmt_idx);
+
+ if( stmt == ::MIR::Statement() )
+ {
+ DEBUG(state << "Remove " << stmt << " - Pure default");
+ to_remove_statements[stmt_idx] = true;
+ continue ;
+ }
+
if( auto* se = stmt.opt_Drop() )
{
// If the drop flag was unset, either remove the drop or remove the drop flag reference
@@ -3595,6 +4484,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
continue ;
}
}
+
+ // HACK: Remove drop if it's of an unused value (TODO: only if it's conditional?)
+ if( se->slot.is_Local() && local_rewrite_table[se->slot.as_Local()] == ~0u )
+ {
+ DEBUG(state << "Remove " << stmt << " - Dropping non-set value");
+ to_remove_statements[stmt_idx] = true;
+ continue ;
+ }
}
visit_mir_lvalues_mut(stmt, lvalue_cb);
@@ -3637,6 +4534,7 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
}
state.set_cur_stmt_term(i);
// Rewrite and advance
+ visit_mir_lvalues_mut(it->terminator, lvalue_cb);
TU_MATCHA( (it->terminator), (e),
(Incomplete,
),
@@ -3650,49 +4548,45 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, lvalue_cb);
e.bb0 = block_rewrite_table[e.bb0];
e.bb1 = block_rewrite_table[e.bb1];
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
e.def_target = block_rewrite_table[e.def_target];
),
(Call,
- if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, lvalue_cb);
- }
- for(auto& v : e.args)
- visit_mir_lvalue_mut(v, ValUsage::Read, lvalue_cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, lvalue_cb);
e.ret_block = block_rewrite_table[e.ret_block];
e.panic_block = block_rewrite_table[e.panic_block];
)
)
// Delete all statements flagged in a bitmap for deletion
- auto stmt_it = it->statements.begin();
- for(auto flag : to_remove_statements)
- {
- if(flag) {
- stmt_it = it->statements.erase(stmt_it);
- }
- else {
- ++ stmt_it;
- }
- }
-
- ++it;
+ assert(it->statements.size() == to_remove_statements.size());
+ auto new_end = ::std::remove_if(it->statements.begin(), it->statements.end(), [&](const auto& s){
+ size_t stmt_idx = (&s - &it->statements.front());
+ return to_remove_statements[stmt_idx];
+ });
+ it->statements.erase(new_end, it->statements.end());
}
+ ++it;
}
+ auto new_blocks_end = ::std::remove_if(fcn.blocks.begin(), fcn.blocks.end(), [&](const auto& bb) {
+ size_t i = &bb - &fcn.blocks.front();
+ if( !visited[i] ) {
+ DEBUG("GC bb" << i);
+ }
+ return !visited[i];
+ });
+ fcn.blocks.erase(new_blocks_end, fcn.blocks.end());
+
+ // NOTE: Drop flags are bool, so can't use the above hack
for(unsigned int i = 0, j = 0; i < n_df; i ++)
{
if( !used_dfs[i] )
@@ -3842,7 +4736,9 @@ void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list)
else if( hir_fcn.m_code )
{
auto& mir = hir_fcn.m_code.get_mir_or_error_mut(Span());
- did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list);
+ bool did_opt = MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list);
+ mir.trans_enum_state = ::MIR::EnumCachePtr(); // Clear MIR enum cache
+ did_inline_on_pass |= did_opt;
}
else
{
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index 49499c86..d4a1d59a 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -40,15 +40,18 @@ extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePath
extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
+extern AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted=true);
extern AST::HigherRankedBounds Parse_HRB(TokenStream& lex);
+extern ::AST::HigherRankedBounds Parse_HRB_Opt(TokenStream& lex);
extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex);
extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out);
extern AST::Attribute Parse_MetaItem(TokenStream& lex);
-extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
+extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, RcString name, TokenStream& lex);
extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true);
extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
+extern AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex);
extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items);
extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items);
extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h
index 5104142b..d5a0eb86 100644
--- a/src/parse/eTokenType.enum.h
+++ b/src/parse/eTokenType.enum.h
@@ -21,6 +21,7 @@ _(TOK_INTERPOLATED_STMT)
_(TOK_INTERPOLATED_BLOCK)
_(TOK_INTERPOLATED_META)
_(TOK_INTERPOLATED_ITEM)
+_(TOK_INTERPOLATED_VIS)
// Value tokens
_(TOK_IDENT)
@@ -58,6 +59,7 @@ _(TOK_SLASH)
_(TOK_DOT)
_(TOK_DOUBLE_DOT)
+_(TOK_DOUBLE_DOT_EQUAL)
_(TOK_TRIPLE_DOT)
_(TOK_EQUAL)
@@ -138,6 +140,7 @@ _(TOK_RWORD_SUPER)
_(TOK_RWORD_PROC)
_(TOK_RWORD_MOVE)
+_(TOK_RWORD_MACRO)
_(TOK_RWORD_ABSTRACT)
_(TOK_RWORD_FINAL)
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 5194e1d8..2735c39e 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -32,8 +32,8 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon);
ExprNodeP Parse_Stmt_Let(TokenStream& lex);
ExprNodeP Parse_Expr0(TokenStream& lex);
ExprNodeP Parse_IfStmt(TokenStream& lex);
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
+ExprNodeP Parse_WhileStmt(TokenStream& lex, RcString lifetime);
+ExprNodeP Parse_ForStmt(TokenStream& lex, RcString lifetime);
ExprNodeP Parse_Expr_Match(TokenStream& lex);
ExprNodeP Parse_Expr1(TokenStream& lex);
ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path tok);
@@ -57,13 +57,18 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
::std::shared_ptr<AST::Module> local_mod;
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK )
+ {
+ GET_TOK(tok, lex);
+ return tok.take_frag_node();
+ }
+
GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
bool last_value_yielded = false;
while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
{
last_value_yielded = false;
- DEBUG("tok = " << tok);
// NOTE: Doc comments can appear within a function and apply to the function
if( lex.parse_state().parent_attrs )
@@ -103,7 +108,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
GET_TOK(tok, lex);
// `union Ident` - contextual keyword
- if( tok.type() == TOK_IDENT && tok.str() == "union" && lex.lookahead(0) == TOK_IDENT ) {
+ if( tok.type() == TOK_IDENT && tok.istr() == "union" && lex.lookahead(0) == TOK_IDENT ) {
PUTBACK(tok, lex);
if( !local_mod ) {
local_mod = lex.parse_state().get_current_mod().add_anon();
@@ -112,7 +117,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
return ExprNodeP();
}
- if( tok.type() == TOK_IDENT && tok.str() == "macro_rules" && lex.lookahead(0) == TOK_EXCLAM )
+ if( tok.type() == TOK_IDENT && tok.istr() == "macro_rules" && lex.lookahead(0) == TOK_EXCLAM )
{
// Special case - create a local module if macro_rules! is seen
// - Allows correct scoping of defined macros
@@ -124,6 +129,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
switch(tok.type())
{
// Items:
+ case TOK_INTERPOLATED_VIS:
case TOK_RWORD_PUB:
// NOTE: Allowed, but doesn't do much
case TOK_RWORD_TYPE:
@@ -185,7 +191,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
if( GET_TOK(tok, lex) == TOK_LIFETIME )
{
// Lifetimes can only precede loops... and blocks?
- ::std::string lifetime = tok.str();
+ auto lifetime = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
switch( GET_TOK(tok, lex) )
@@ -248,6 +254,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
case TOK_BRACE_OPEN:
{ PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); }
+ // If the block is followed by `.` or `?`, it's actually an expression!
if( lex.lookahead(0) == TOK_DOT || lex.lookahead(0) == TOK_QMARK ) {
lex.putback( Token(Token::TagTakeIP(), InterpolatedFragment(InterpolatedFragment::EXPR, ret.release())) );
return Parse_ExprBlockLine_Stmt(lex, *add_silence);
@@ -284,7 +291,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
// If a braced macro invocation is the first part of a statement, don't expect a semicolon
if( lex.lookahead(1) == TOK_BRACE_OPEN || (lex.lookahead(1) == TOK_IDENT && lex.lookahead(2) == TOK_BRACE_OPEN) ) {
lex.getToken();
- return Parse_ExprMacro(lex, tok.str());
+ return Parse_ExprMacro(lex, tok.istr());
}
}
// Fall through to the statement code
@@ -316,7 +323,7 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon)
}
/// While loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
+ExprNodeP Parse_WhileStmt(TokenStream& lex, RcString lifetime)
{
Token tok;
@@ -342,12 +349,12 @@ ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
}
}
/// For loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime)
+ExprNodeP Parse_ForStmt(TokenStream& lex, RcString lifetime)
{
Token tok;
// Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
+ auto pat = Parse_Pattern(lex, false);
GET_CHECK_TOK(tok, lex, TOK_RWORD_IN);
ExprNodeP val;
{
@@ -435,6 +442,9 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex)
arm.m_attrs = Parse_ItemAttrs(lex);
+ // HACK: Questionably valid, but 1.29 librustc/hir/lowering.rs needs this
+ if( LOOK_AHEAD(lex) == TOK_PIPE )
+ GET_TOK(tok, lex);
do {
// Refutable pattern
arm.m_patterns.push_back( Parse_Pattern(lex, true) );
@@ -461,6 +471,17 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex)
return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) );
}
+/// "do catch" block
+ExprNodeP Parse_Expr_Try(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ //Token tok;
+
+ auto inner = Parse_ExprBlockNode(lex);
+ //TODO(lex.point_span(), "do catch");
+ return NEWNODE(AST::ExprNode_Try, ::std::move(inner));
+}
+
/// Parses the 'stmt' fragment specifier
/// - Flow control
/// - Expressions
@@ -503,10 +524,10 @@ ExprNodeP Parse_Stmt(TokenStream& lex)
case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break;
default: throw ParseError::BugCheck(/*lex,*/ "continue/break");
}
- ::std::string lifetime;
+ RcString lifetime;
if( GET_TOK(tok, lex) == TOK_LIFETIME )
{
- lifetime = tok.str();
+ lifetime = tok.istr(); // TODO: Hygine?
GET_TOK(tok, lex);
}
ExprNodeP val;
@@ -706,7 +727,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 +767,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,
@@ -920,26 +948,26 @@ ExprNodeP Parse_ExprFC(TokenStream& lex)
switch(GET_TOK(tok, lex))
{
case TOK_IDENT: {
- AST::PathNode path( mv$(tok.str()) , {});
+ AST::PathNode pn( tok.istr() , {});
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(pn), Parse_ParenList(lex) );
break;
case TOK_DOUBLE_COLON:
GET_CHECK_TOK(tok, lex, TOK_LT);
- path.args() = Parse_Path_GenericList(lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ pn.args() = Parse_Path_GenericList(lex);
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(pn), Parse_ParenList(lex) );
break;
default:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) );
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), pn.name() );
PUTBACK(tok, lex);
break;
}
break; }
case TOK_INTEGER:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) );
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), RcString::new_interned(FMT(tok.intval())) );
break;
default:
throw ParseError::Unexpected(lex, mv$(tok));
@@ -1005,7 +1033,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
}
CHECK_TOK(tok, TOK_IDENT);
auto h = lex.getHygiene();
- auto name = mv$(tok.str());
+ auto name = tok.istr();
ExprNodeP val;
if( lex.lookahead(0) != TOK_COLON )
@@ -1110,6 +1138,23 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
return Parse_WhileStmt(lex, "");
case TOK_RWORD_FOR:
return Parse_ForStmt(lex, "");
+ case TOK_RWORD_DO:
+ if( TARGETVER_1_29 )
+ {
+ // `do catch` - stabilised later as `try`
+ if( GET_TOK(tok, lex) == TOK_IDENT && tok.istr() == "catch" )
+ {
+ return Parse_Expr_Try(lex);
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
case TOK_RWORD_MATCH:
return Parse_Expr_Match(lex);
case TOK_RWORD_IF:
@@ -1275,10 +1320,10 @@ ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path path)
}
Token tok;
- ::std::string name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
- ::std::string ident;
+ auto name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
+ RcString ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
+ ident = tok.istr();
}
else {
PUTBACK(tok, lex);
diff --git a/src/parse/interpolated_fragment.cpp b/src/parse/interpolated_fragment.cpp
index d8a8bc43..634309a5 100644
--- a/src/parse/interpolated_fragment.cpp
+++ b/src/parse/interpolated_fragment.cpp
@@ -31,6 +31,9 @@ InterpolatedFragment::~InterpolatedFragment()
case InterpolatedFragment::ITEM:
delete reinterpret_cast<AST::Named<AST::Item>*>(m_ptr);
break;
+ case InterpolatedFragment::VIS:
+ delete reinterpret_cast<AST::Visibility*>(m_ptr);
+ break;
}
}
}
@@ -82,6 +85,11 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v):
m_ptr( new TypeRef(mv$(v)) )
{
}
+InterpolatedFragment::InterpolatedFragment(AST::Visibility v):
+ m_type( InterpolatedFragment::VIS ),
+ m_ptr( new AST::Visibility(mv$(v)) )
+{
+}
::std::ostream& operator<<(::std::ostream& os, InterpolatedFragment const& x)
{
@@ -117,6 +125,9 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v):
const auto& named_item = *reinterpret_cast<const AST::Named<AST::Item>*>(x.m_ptr);
os << "item[" << named_item.data.tag_str() << "(" << named_item.name << ")]";
} break;
+ case InterpolatedFragment::VIS:
+ os << "vis[" << *reinterpret_cast<const AST::Visibility*>(x.m_ptr) << "]";
+ break;
}
return os;
}
diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp
index 36539fb0..1e69fe26 100644
--- a/src/parse/interpolated_fragment.hpp
+++ b/src/parse/interpolated_fragment.hpp
@@ -12,6 +12,7 @@
class TypeRef;
class TokenTree;
namespace AST {
+ typedef bool Visibility;
class Pattern;
class Path;
class ExprNode;
@@ -37,6 +38,7 @@ public:
META,
ITEM,
+ VIS,
} m_type;
// Owned type-pruned pointer
@@ -53,6 +55,7 @@ public:
InterpolatedFragment(::AST::Named<AST::Item> );
~InterpolatedFragment();
InterpolatedFragment(Type , ::AST::ExprNode*);
+ InterpolatedFragment(AST::Visibility); // :vis
TokenTree& as_tt() { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
const TokenTree& as_tt() const { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp
index 8376eeee..90c8ccbe 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),
@@ -153,6 +155,7 @@ static const struct {
TOKENT("in", TOK_RWORD_IN),
TOKENT("let", TOK_RWORD_LET),
TOKENT("loop", TOK_RWORD_LOOP),
+ TOKENT("macro", TOK_RWORD_MACRO),
TOKENT("match", TOK_RWORD_MATCH),
TOKENT("mod", TOK_RWORD_MOD),
TOKENT("move", TOK_RWORD_MOVE),
@@ -402,9 +405,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);
@@ -529,7 +536,7 @@ Token Lexer::getTokenInt()
str += ch;
}
}
- return Token(TOK_BYTESTRING, str);
+ return Token(TOK_BYTESTRING, mv$(str));
}
// Byte constant
else if( ch == '\'' ) {
@@ -601,7 +608,7 @@ Token Lexer::getTokenInt()
m_next_tokens.push_back(TOK_SQUARE_CLOSE);
m_next_tokens.push_back(Token(TOK_STRING, mv$(str)));
m_next_tokens.push_back(TOK_EQUAL);
- m_next_tokens.push_back(Token(TOK_IDENT, "doc"));
+ m_next_tokens.push_back(Token(TOK_IDENT, RcString::new_interned("doc")));
m_next_tokens.push_back(TOK_SQUARE_OPEN);
if(is_pdoc)
m_next_tokens.push_back(TOK_EXCLAM);
@@ -664,7 +671,7 @@ Token Lexer::getTokenInt()
m_next_tokens.push_back(TOK_SQUARE_CLOSE);
m_next_tokens.push_back(Token(TOK_STRING, mv$(str)));
m_next_tokens.push_back(TOK_EQUAL);
- m_next_tokens.push_back(Token(TOK_IDENT, "doc"));
+ m_next_tokens.push_back(Token(TOK_IDENT, RcString::new_interned("doc")));
m_next_tokens.push_back(TOK_SQUARE_OPEN);
if(is_pdoc)
m_next_tokens.push_back(TOK_EXCLAM);
@@ -697,7 +704,7 @@ Token Lexer::getTokenInt()
ch = this->getc();
}
this->ungetc();
- return Token(TOK_LIFETIME, str);
+ return Token(TOK_LIFETIME, RcString::new_interned(str));
}
else {
throw ParseError::Todo("Lex Fail - Expected ' after character constant");
@@ -721,7 +728,7 @@ Token Lexer::getTokenInt()
str += ch;
}
}
- return Token(TOK_STRING, str);
+ return Token(TOK_STRING, mv$(str));
}
default:
assert(!"bugcheck");
@@ -799,7 +806,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte)
}
}
}
- return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, val);
+ return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, mv$(val));
}
Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2)
{
@@ -819,7 +826,7 @@ Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2)
if( str < RWORDS[i].chars ) break;
if( str == RWORDS[i].chars ) return Token((enum eTokenType)RWORDS[i].type);
}
- return Token(TOK_IDENT, mv$(str));
+ return Token(TOK_IDENT, RcString::new_interned(str));
}
// Takes the VERY lazy way of reading the float into a string then passing to strtod
diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp
index 1bb30985..f2a5343b 100644
--- a/src/parse/parseerror.cpp
+++ b/src/parse/parseerror.cpp
@@ -61,7 +61,7 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok);
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
// m_tok( mv$(tok) )
@@ -69,22 +69,22 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Tok
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok << ", expected " << exp);
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
{
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected " << tok << ", expected ";
- bool f = true;
- for(auto v: exp) {
- if(!f)
- ::std::cout << " or ";
- f = false;
- ::std::cout << Token::typestr(v);
- }
- ::std::cout << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok << ", expected one of " << FMT_CB(os, {
+ bool f = true;
+ for(auto v: exp) {
+ if(!f)
+ os << " or ";
+ f = false;
+ os << Token::typestr(v);
+ }
+ }));
}
ParseError::Unexpected::~Unexpected() throw()
{
diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp
index d103840e..8bfd20de 100644
--- a/src/parse/paths.cpp
+++ b/src/parse/paths.cpp
@@ -39,6 +39,9 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, generic_mode));
}
+ case TOK_RWORD_CRATE:
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ return Parse_Path(lex, true, generic_mode);
case TOK_DOUBLE_COLON:
return Parse_Path(lex, true, generic_mode);
@@ -80,8 +83,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
Token tok;
if( is_abs )
{
- if( GET_TOK(tok, lex) == TOK_STRING ) {
- ::std::string cratename = tok.str();
+ // QUIRK: `::crate::foo` is valid (semi-surprisingly)
+ if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_CRATE);
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ return AST::Path("", Parse_PathNodes(lex, generic_mode));
+ }
+ else if( GET_TOK(tok, lex) == TOK_STRING ) {
+ auto cratename = RcString::new_interned(tok.str());
GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
return AST::Path(cratename, Parse_PathNodes(lex, generic_mode));
}
@@ -94,6 +103,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
// TODO: TOK_INTERPOLATED_IDENT?
GET_CHECK_TOK(tok, lex, TOK_IDENT);
auto hygine = lex.getHygiene();
+ DEBUG("hygine = " << hygine);
PUTBACK(tok, lex);
return AST::Path(AST::Path::TagRelative(), mv$(hygine), Parse_PathNodes(lex, generic_mode));
}
@@ -112,7 +122,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::AST::PathParams params;
CHECK_TOK(tok, TOK_IDENT);
- auto component = mv$( tok.str() );
+ auto component = mv$( tok.istr() );
GET_TOK(tok, lex);
if( generic_mode == PATH_GENERIC_TYPE )
@@ -133,18 +143,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
auto ps = lex.start_span();
DEBUG("Fn() hack");
::std::vector<TypeRef> args;
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- {
- // Empty list
- }
- else
- {
- PUTBACK(tok, lex);
- do {
- // TODO: Trailing commas
- args.push_back( Parse_Type(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- }
+ do {
+ // Trailing comma or empty list support
+ if( lex.lookahead(0) == TOK_PAREN_CLOSE ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ args.push_back( Parse_Type(lex) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_PAREN_CLOSE);
TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) );
@@ -160,7 +166,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
params = ::AST::PathParams {
{},
::make_vec1( TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(args)) ),
- ::make_vec1( ::std::make_pair( ::std::string("Output"), mv$(ret_type) ) )
+ ::make_vec1( ::std::make_pair( RcString::new_interned("Output"), mv$(ret_type) ) )
};
GET_TOK(tok, lex);
@@ -204,7 +210,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::std::vector<TypeRef> types;
::std::vector<AST::LifetimeRef> lifetimes;
- ::std::vector< ::std::pair< ::std::string, TypeRef > > assoc_bounds;
+ ::std::vector< ::std::pair< RcString, TypeRef > > assoc_bounds;
do {
if( LOOK_AHEAD(lex) == TOK_GT || LOOK_AHEAD(lex) == TOK_DOUBLE_GT || LOOK_AHEAD(lex) == TOK_GTE || LOOK_AHEAD(lex) == TOK_DOUBLE_GT_EQUAL ) {
@@ -219,7 +225,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
case TOK_IDENT:
if( LOOK_AHEAD(lex) == TOK_EQUAL )
{
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
assoc_bounds.push_back( ::std::make_pair( mv$(name), Parse_Type(lex,false) ) );
break;
diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp
index e2949a63..cd73c378 100644
--- a/src/parse/pattern.cpp
+++ b/src/parse/pattern.cpp
@@ -46,7 +46,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( tok.type() == TOK_IDENT && lex.lookahead(0) == TOK_EXCLAM )
{
lex.getToken();
- return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.str(), lex)));
+ return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.istr(), lex)));
}
if( tok.type() == TOK_INTERPOLATED_PATTERN )
{
@@ -87,12 +87,12 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( expect_bind )
{
CHECK_TOK(tok, TOK_IDENT);
- auto bind_name = Ident(lex.getHygiene(), mv$(tok.str()));
+ auto bind_name = lex.get_ident(mv$(tok));
// If there's no '@' after it, it's a name binding only (_ pattern)
if( GET_TOK(tok, lex) != TOK_AT )
{
PUTBACK(tok, lex);
- return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(mv$(ps)), mv$(bind_name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(bind_name), bind_type, is_mut);
}
binding = AST::PatternBinding( mv$(bind_name), bind_type, is_mut );
@@ -113,24 +113,25 @@ 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:
- binding = AST::PatternBinding( Ident(lex.getHygiene(), mv$(tok.str())), bind_type/*MOVE*/, is_mut/*false*/ );
+ binding = AST::PatternBinding( lex.get_ident(mv$(tok)), bind_type/*MOVE*/, is_mut/*false*/ );
GET_TOK(tok, lex); // '@'
GET_TOK(tok, lex); // Match lex.putback() below
break;
default: { // Maybe bind
- Ident name = Ident(lex.getHygiene(), mv$(tok.str()));
+ auto name = lex.get_ident(mv$(tok));
// if the pattern can be refuted (i.e this could be an enum variant), return MaybeBind
if( is_refutable ) {
assert(bind_type == ::AST::PatternBinding::Type::MOVE);
assert(is_mut == false);
- return AST::Pattern(AST::Pattern::TagMaybeBind(), lex.end_span(mv$(ps)), mv$(name));
+ return AST::Pattern(AST::Pattern::TagMaybeBind(), lex.end_span(ps), mv$(name));
}
// Otherwise, it IS a binding
else {
- return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(mv$(ps)), mv$(name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(name), bind_type, is_mut);
}
break;}
}
@@ -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");
@@ -188,11 +191,11 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
switch( GET_TOK(tok, lex) )
{
case TOK_UNDERSCORE:
- return AST::Pattern( lex.end_span(mv$(ps)), AST::Pattern::Data() );
+ return AST::Pattern( lex.end_span(ps), AST::Pattern::Data() );
//case TOK_DOUBLE_DOT:
// return AST::Pattern( AST::Pattern::TagWildcard() );
case TOK_RWORD_BOX:
- return AST::Pattern( AST::Pattern::TagBox(), lex.end_span(mv$(ps)), Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagBox(), lex.end_span(ps), Parse_Pattern(lex, is_refutable) );
case TOK_DOUBLE_AMP:
lex.putback(TOK_AMP);
case TOK_AMP: {
@@ -203,7 +206,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
is_mut = true;
else
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagReference(), lex.end_span(mv$(ps)), is_mut, Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagReference(), lex.end_span(ps), is_mut, Parse_Pattern(lex, is_refutable) );
}
case TOK_RWORD_SELF:
case TOK_RWORD_SUPER:
@@ -221,44 +224,44 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
{
auto dt = tok.datatype();
// TODO: Ensure that the type is ANY or a signed integer
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
}
else if( tok.type() == TOK_FLOAT )
{
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
}
else
{
throw ParseError::Unexpected(lex, tok, {TOK_INTEGER, TOK_FLOAT});
}
case TOK_FLOAT:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
case TOK_INTEGER:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
case TOK_RWORD_TRUE:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
case TOK_RWORD_FALSE:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
case TOK_STRING:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
case TOK_BYTESTRING:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
case TOK_INTERPOLATED_EXPR: {
auto e = tok.take_frag_node();
if( auto* n = dynamic_cast<AST::ExprNode_String*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
+ }
+ else if( auto* n = dynamic_cast<AST::ExprNode_ByteString*>(e.get()) ) {
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString({ mv$(n->m_value) }) );
}
- //else if( auto* n = dynamic_cast<AST::ExprNode_ByteString*>(e.get()) ) {
- // return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_ByteString( mv$(n->m_value) ) );
- //}
else if( auto* n = dynamic_cast<AST::ExprNode_Bool*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Integer*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Float*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
}
else {
TODO(lex.point_span(), "Convert :expr into a pattern value - " << *e);
@@ -266,7 +269,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
} break;
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagTuple(), lex.end_span(mv$(ps)), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagTuple(), lex.end_span(ps), Parse_PatternTuple(lex, is_refutable) );
case TOK_SQUARE_OPEN:
return Parse_PatternReal_Slice(lex, is_refutable);
default:
@@ -280,12 +283,12 @@ AST::Pattern Parse_PatternReal_Path(TokenStream& lex, ProtoSpan ps, AST::Path pa
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagNamedTuple(), lex.end_span(mv$(ps)), mv$(path), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), Parse_PatternTuple(lex, is_refutable) );
case TOK_BRACE_OPEN:
return Parse_PatternStruct(lex, ps, mv$(path), is_refutable);
default:
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Named(mv$(path)) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Named(mv$(path)) );
}
}
@@ -323,7 +326,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( has_binding ) {
if(is_split)
- ERROR(lex.end_span(mv$(ps)), E0000, "Multiple instances of .. in a slice pattern");
+ ERROR(lex.end_span(ps), E0000, "Multiple instances of .. in a slice pattern");
inner_binding = mv$(binding);
is_split = true;
@@ -346,13 +349,13 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( is_split )
{
- return ::AST::Pattern( lex.end_span(mv$(ps)), ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
}
else
{
assert( !inner_binding.is_valid() );
assert( trailing.empty() );
- return ::AST::Pattern( lex.end_span(mv$(ps)), ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
}
}
@@ -452,11 +455,11 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
i ++;
}
- return AST::Pattern(AST::Pattern::TagNamedTuple(), lex.end_span(mv$(ps)), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
+ return AST::Pattern(AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
}
bool is_exhaustive = true;
- ::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats;
+ ::std::vector< ::std::pair< RcString, AST::Pattern> > subpats;
do {
GET_TOK(tok, lex);
DEBUG("tok = " << tok);
@@ -497,7 +500,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
CHECK_TOK(tok, TOK_IDENT);
auto field_ident = lex.get_ident(mv$(tok));
- ::std::string field_name;
+ RcString field_name;
GET_TOK(tok, lex);
AST::Pattern pat;
@@ -521,6 +524,6 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_BRACE_CLOSE);
- return AST::Pattern(AST::Pattern::TagStruct(), lex.end_span(mv$(ps)), ::std::move(path), ::std::move(subpats), is_exhaustive);
+ return AST::Pattern(AST::Pattern::TagStruct(), lex.end_span(ps), ::std::move(path), ::std::move(subpats), is_exhaustive);
}
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index bc001c99..e81055ec 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -18,14 +18,17 @@
#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>
+#include <macro_rules/macro_rules.hpp>
+#include <path.h>
template<typename T>
Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
auto ps = lex.start_span();
auto v = f();
return Spanned<T> {
- lex.end_span( mv$(ps) ),
+ lex.end_span(ps),
mv$(v)
};
}
@@ -34,7 +37,7 @@ Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
// Check the next two tokens
#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
-::std::string dirname(::std::string input) {
+::helpers::path dirname(::std::string input) {
while( input.size() > 0 && input.back() != '/' && input.back() != '\\' ) {
input.pop_back();
}
@@ -47,10 +50,20 @@ AST::Attribute Parse_MetaItem(TokenStream& lex);
void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs);
bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv);
-//::AST::Path Parse_Publicity(TokenStream& lex)
-bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
+::AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted/*=true*/)
{
Token tok;
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_VIS )
+ {
+ GET_TOK(tok, lex);
+ return tok.take_frag_vis();
+ }
+ if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE )
+ {
+ // TODO: Return a path that indicates the entire current crate
+ GET_TOK(tok, lex);
+ return true;
+ }
if( LOOK_AHEAD(lex) == TOK_RWORD_PUB )
{
GET_TOK(tok, lex);
@@ -98,12 +111,12 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
GET_CHECK_TOK(tok, lex, TOK_IDENT);
case TOK_RWORD_IN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON )
{
GET_TOK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
}
break;
default:
@@ -137,7 +150,7 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
switch(GET_TOK(tok, lex))
{
case TOK_LIFETIME:
- rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), tok.str())));
+ rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), lex.get_ident(mv$(tok))));
break;
default:
throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME));
@@ -163,7 +176,7 @@ namespace {
AST::LifetimeRef get_LifetimeRef(TokenStream& lex, Token tok)
{
CHECK_TOK(tok, TOK_LIFETIME);
- return AST::LifetimeRef(/*lex.point_span(), */Ident(lex.getHygiene(), mv$(tok.str())));
+ return AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(mv$(tok)));
}
}
/// Parse type parameters in a definition
@@ -230,7 +243,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
GET_TOK(tok, lex);
if( tok.type() == TOK_IDENT )
{
- ::std::string param_name = mv$(tok.str());
+ auto param_name = tok.istr();
ret.add_ty_param( AST::TypeParam( lex.point_span(), ::std::move(attrs), param_name ) );
auto param_ty = TypeRef(lex.point_span(), param_name);
@@ -248,7 +261,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
}
else if( tok.type() == TOK_LIFETIME )
{
- auto param_name = tok.str();
+ auto param_name = tok.istr();
auto ref = get_LifetimeRef(lex, mv$(tok));
ret.add_lft_param(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), param_name) ));
if( GET_TOK(tok, lex) == TOK_COLON )
@@ -499,7 +512,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
PUTBACK(tok, lex);
}
- return AST::Function(lex.end_span( mv$(ps) ), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
+ return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
}
AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const)
@@ -609,7 +622,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -628,6 +641,140 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
}
}
+AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex)
+{
+ Token tok;
+
+ auto item_attrs = Parse_ItemAttrs(lex);
+ SET_ATTRS(lex, item_attrs);
+
+ auto ps = lex.start_span();
+ {
+ ::AST::MacroInvocation inv;
+ if( Parse_MacroInvocation_Opt(lex, inv) )
+ {
+ return AST::Named<AST::Item>( lex.end_span(ps), mv$(item_attrs), false, "", AST::Item(mv$(inv)) );
+ }
+ }
+
+ GET_TOK(tok, lex);
+ bool is_specialisable = false;
+ if( tok.type() == TOK_IDENT && tok.istr() == "default" ) {
+ is_specialisable = true;
+ GET_TOK(tok, lex);
+ }
+ // TODO: Mark specialisation
+ (void)is_specialisable;
+
+ bool fn_is_const = false;
+ bool fn_is_unsafe = false;
+ ::std::string abi = ABI_RUST;
+
+ RcString name;
+ ::AST::Item rv;
+ switch(tok.type())
+ {
+ case TOK_RWORD_STATIC: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto ty = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ ::AST::Expr val;
+ if(GET_TOK(tok, lex) == TOK_EQUAL) {
+ val = Parse_Expr(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ rv = ::AST::Static(::AST::Static::STATIC, mv$(ty), val);
+ break; }
+ case TOK_RWORD_CONST: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto ty = Parse_Type(lex);
+
+ ::AST::Expr val;
+ if(GET_TOK(tok, lex) == TOK_EQUAL) {
+ val = Parse_Expr(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ rv = ::AST::Static(AST::Static::CONST, mv$(ty), val);
+ break; }
+ // Associated type
+ case TOK_RWORD_TYPE: {
+ auto atype_params = ::AST::GenericParams { };
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ // Bounded associated type
+ Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF));
+ GET_TOK(tok, lex);
+ }
+ if( tok.type() == TOK_RWORD_WHERE ) {
+ throw ParseError::Todo(lex, "Where clause on associated type");
+ }
+
+ TypeRef default_type = TypeRef( lex.point_span() );
+ if( tok.type() == TOK_EQUAL ) {
+ default_type = Parse_Type(lex);
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_SEMICOLON);
+ rv = ::AST::TypeAlias( mv$(atype_params), mv$(default_type) );
+ break; }
+
+ // Functions (possibly unsafe)
+ case TOK_RWORD_UNSAFE:
+ fn_is_unsafe = true;
+ if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
+ case TOK_RWORD_EXTERN:
+ {
+ abi = "C";
+ if( GET_TOK(tok, lex) == TOK_STRING )
+ abi = tok.str();
+ else
+ PUTBACK(tok, lex);
+
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_RWORD_FN);
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ // Self allowed, prototype-form allowed (optional names and no code)
+ auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
+ if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
+ {
+ PUTBACK(tok, lex);
+ // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
+ lex.push_hygine();
+ fcn.set_code( Parse_ExprBlock(lex) );
+ lex.pop_hygine();
+ }
+ else if( tok.type() == TOK_SEMICOLON )
+ {
+ // Accept it
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ rv = ::std::move(fcn);
+ break; }
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+
+ return ::AST::Named<::AST::Item>( lex.end_span(ps), mv$(item_attrs), true, mv$(name), mv$(rv) );
+}
+
AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -649,9 +796,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;
@@ -680,131 +825,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items
{
PUTBACK(tok, lex);
- auto item_attrs = Parse_ItemAttrs(lex);
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
- {
- ::AST::MacroInvocation inv;
- if( Parse_MacroInvocation_Opt(lex, inv) )
- {
- trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
- continue ;
- }
- GET_TOK(tok, lex);
- }
-
- bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
- is_specialisable = true;
- GET_TOK(tok, lex);
- }
- // TODO: Mark specialisation
- (void)is_specialisable;
-
- bool fn_is_const = false;
- bool fn_is_unsafe = false;
- ::std::string abi = ABI_RUST;
- switch(tok.type())
- {
- case TOK_RWORD_STATIC: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto ty = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- ::AST::Expr val;
- if(GET_TOK(tok, lex) == TOK_EQUAL) {
- val = Parse_Expr(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::STATIC, mv$(ty), val) );
- break; }
- case TOK_RWORD_CONST: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto ty = Parse_Type(lex);
-
- ::AST::Expr val;
- if(GET_TOK(tok, lex) == TOK_EQUAL) {
- val = Parse_Expr(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::CONST, mv$(ty), val) );
- break; }
- // Associated type
- case TOK_RWORD_TYPE: {
- auto atype_params = ::AST::GenericParams { };
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- // Bounded associated type
- Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF));
- GET_TOK(tok, lex);
- }
- if( tok.type() == TOK_RWORD_WHERE ) {
- throw ParseError::Todo(lex, "Where clause on associated type");
- }
-
- TypeRef default_type = TypeRef( lex.point_span() );
- if( tok.type() == TOK_EQUAL ) {
- default_type = Parse_Type(lex);
- GET_TOK(tok, lex);
- }
-
- CHECK_TOK(tok, TOK_SEMICOLON);
- trait.add_type( ::std::move(name), mv$(item_attrs), ::std::move(default_type) );
- trait.items().back().data.as_Type().params() = mv$(atype_params);
- break; }
-
- // Functions (possibly unsafe)
- case TOK_RWORD_UNSAFE:
- fn_is_unsafe = true;
- if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
- case TOK_RWORD_EXTERN:
- {
- abi = "C";
- if( GET_TOK(tok, lex) == TOK_STRING )
- abi = tok.str();
- else
- PUTBACK(tok, lex);
-
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_RWORD_FN);
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- // Self allowed, prototype-form allowed (optional names and no code)
- auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
- if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
- lex.push_hygine();
- fcn.set_code( Parse_ExprBlock(lex) );
- lex.pop_hygine();
- }
- else if( tok.type() == TOK_SEMICOLON )
- {
- // Accept it
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok);
- }
+ trait.items().push_back( Parse_Trait_Item(lex) );
}
return trait;
@@ -842,7 +863,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
SET_ATTRS(lex, item_attrs);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
// Tuple-like variants
if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
{
@@ -880,7 +901,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
auto field_attrs = Parse_ItemAttrs(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
fields.push_back( ::AST::StructItem(mv$(field_attrs), true, mv$(name), mv$(ty)) );
@@ -945,7 +966,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
@@ -988,34 +1009,56 @@ 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);
- ::std::string name = mv$(tok.str());
+ 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});
+ }
+
+ auto name = tok.istr();
switch(GET_TOK(tok, lex))
{
case TOK_EQUAL:
switch(GET_TOK(tok, lex))
{
case TOK_STRING:
- return AST::Attribute(lex.end_span(mv$(ps)), name, tok.str());
+ 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(mv$(ps)), name, mv$(v->m_value));
+ return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value));
}
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);
@@ -1031,10 +1074,10 @@ AST::Attribute Parse_MetaItem(TokenStream& lex)
items.push_back(Parse_MetaItem(lex));
} while(GET_TOK(tok, lex) == TOK_COMMA);
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::Attribute(lex.end_span(mv$(ps)), name, mv$(items)); }
+ return AST::Attribute(lex.end_span(ps), name, mv$(items)); }
default:
PUTBACK(tok, lex);
- return AST::Attribute(lex.end_span(mv$(ps)), name);
+ return AST::Attribute(lex.end_span(ps), name);
}
}
@@ -1145,7 +1188,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( Parse_MacroInvocation_Opt(lex, inv) )
{
impl.add_macro_invocation( mv$(inv) );
- impl.items().back().data->attrs = mv$(item_attrs);
+ impl.items().back().attrs = mv$(item_attrs);
return ;
}
}
@@ -1156,7 +1199,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_TOK(tok, lex);
bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
+ if( tok.type() == TOK_IDENT && tok.istr() == "default" ) {
is_specialisable = true;
GET_TOK(tok, lex);
}
@@ -1168,10 +1211,11 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
{
case TOK_RWORD_TYPE: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- impl.add_type(is_public, is_specialisable, name, Parse_Type(lex));
+ auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ impl.add_type(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, name, mv$(ty));
break; }
case TOK_RWORD_UNSAFE:
fn_is_unsafe = true;
@@ -1183,7 +1227,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
{
CHECK_TOK(tok, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
@@ -1191,7 +1235,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) );
+ impl.add_static( lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(i) );
break ;
}
else if( tok.type() == TOK_RWORD_UNSAFE )
@@ -1218,19 +1262,16 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
// TODO: Hygine on function names? - Not in impl blocks?
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
DEBUG("Function " << name);
// - Self allowed, can't be prototype-form
auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const);
- impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn));
+ impl.add_function(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(fcn));
break; }
default:
throw ParseError::Unexpected(lex, tok);
}
-
- impl.items().back().data->span = lex.end_span(mv$(ps));
- impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
}
AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::AttributeList& block_attrs)
@@ -1255,16 +1296,13 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
{
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
// parse function as prototype
// - no self, is prototype, is unsafe and not const
auto i = ::AST::Item( Parse_FunctionDef(lex, abi, false, true, true,false) );
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(mv$(ps));
-
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
case TOK_RWORD_STATIC: {
bool is_mut = false;
@@ -1273,62 +1311,104 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
else
PUTBACK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto type = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() ));
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(mv$(ps));
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
+ break; }
+ case TOK_RWORD_TYPE: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ auto sp = lex.end_span(ps);
+ //TODO(sp, "Extern type");
+ auto i = ::AST::Item(::AST::TypeAlias( ::AST::GenericParams(), ::TypeRef(sp) ));
+ rv.add_item( AST::Named<AST::Item> { mv$(sp), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC, TOK_RWORD_TYPE});
}
}
return rv;
}
-void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+/// Parse multiple items from a use "statement"
+void Parse_Use_Inner(TokenStream& lex, ::std::vector<AST::UseItem::Ent>& entries, AST::Path& path)
{
- fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import
-}
-void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- TRACE_FUNCTION;
-
Token tok;
- do {
- AST::Path path;
- ::std::string name;
- if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) {
- path = ::AST::Path(base_path);
- name = base_path[base_path.size()-1].name();
- }
- else if( tok.type() == TOK_BRACE_CLOSE ) {
- break ;
- }
- else {
- CHECK_TOK(tok, TOK_IDENT);
- path = base_path + AST::PathNode(tok.str(), {});
- name = mv$(tok.str());
- }
- if( GET_TOK(tok, lex) == TOK_RWORD_AS ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
+ do
+ {
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_IDENT:
+ path.append( AST::PathNode( tok.istr(), {}) );
+ break;
+ case TOK_BRACE_OPEN:
+ // Can't be an empty list
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ // Keep looping until a comma
+ do {
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ // Trailing comma
+ GET_TOK(tok, lex);
+ break;
+ }
+ // - Handle `self` in braces differently
+ else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) {
+ GET_TOK(tok, lex);
+ auto name = path.nodes().back().name();
+ if( LOOK_AHEAD(lex) == TOK_RWORD_AS ) {
+ GET_TOK(tok, lex);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+ }
+ else {
+ size_t l = path.nodes().size();
+
+ Parse_Use_Inner(lex, entries, path);
+
+ assert(l <= path.nodes().size());
+ path.nodes().resize( l );
+ }
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ return;
+ case TOK_STAR:
+ entries.push_back({ lex.point_span(), AST::Path(path), "" });
+ return ;
+ default:
+ throw ParseError::Unexpected(lex, tok);
}
- fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
+ } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON );
+
+ RcString name;
-void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+ // NOTE: The above loop has to run once, so the last token HAS to have been an ident
+ if( tok.type() == TOK_RWORD_AS )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
+ name = path.nodes().back().name();
+ }
+
+ // TODO: Get a span covering the final node.
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+}
+::AST::UseItem Parse_Use(TokenStream& lex)
{
TRACE_FUNCTION;
@@ -1337,10 +1417,13 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
::std::vector<AST::PathNode> nodes;
ProtoSpan span_start = lex.start_span();
+ ::std::vector<AST::UseItem::Ent> entries;
+
switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_SELF:
path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
case TOK_RWORD_SUPER: {
unsigned int count = 1;
@@ -1350,9 +1433,11 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
count += 1;
}
path = AST::Path( AST::Path::TagSuper(), count, {} );
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break; }
- case TOK_IDENT:
- path.append( AST::PathNode(mv$(tok.str()), {}) );
+ case TOK_RWORD_CRATE:
+ // 1.29 absolute path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
// Leading :: is allowed and ignored for the $crate feature
case TOK_DOUBLE_COLON:
@@ -1361,77 +1446,35 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
if( LOOK_AHEAD(lex) == TOK_STRING )
{
GET_CHECK_TOK(tok, lex, TOK_STRING);
- path = ::AST::Path(tok.str(), {});
+ path = ::AST::Path(RcString::new_interned(tok.str()), {});
}
- else {
+ else
+ {
PUTBACK(tok, lex);
}
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, path, fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- return;
case TOK_INTERPOLATED_PATH:
path = mv$(tok.frag_path());
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
default:
- throw ParseError::Unexpected(lex, tok);
- }
- while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
- {
- if( GET_TOK(tok, lex) == TOK_IDENT )
- {
- path.append( AST::PathNode( mv$(tok.str()), {}) );
- }
- else
- {
- //path.set_span( lex.end_span(span_start) );
- switch( tok.type() )
- {
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, mv$(path), fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break ;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- break ;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- // early return - This branch is either the end of the use statement, or a syntax error
- return ;
- }
- }
- //path.set_span( lex.end_span(span_start) );
-
- ::std::string name;
- // This should only be allowed if the last token was an ident
- // - Above checks ensure this
- if( tok.type() == TOK_RWORD_AS )
- {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else
- {
PUTBACK(tok, lex);
- ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
- name = path.nodes().back().name();
+ break;
}
- fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
+ Parse_Use_Inner(lex, entries, path);
+
+ return AST::UseItem { lex.end_span(span_start), mv$(entries) };
}
-::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
+::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, RcString name, TokenStream& lex)
{
Token tok;
- ::std::string ident;
+ RcString ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
+ ident = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1448,14 +1491,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
{
// Good
}
+ else if( lex.lookahead(0) == TOK_INTERPOLATED_PATH && lex.lookahead(1) == TOK_EXCLAM )
+ {
+ // Also good.
+ }
else
{
return false;
}
auto ps = lex.start_span();
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = tok.str();
+ auto name_path = Parse_Path(lex, PATH_GENERIC_NONE);
+ ASSERT_BUG(lex.point_span(), name_path.nodes().size() == 1, "TODO: Support multi-component paths in macro invocations");
+ auto name = name_path.nodes()[0].name();
GET_CHECK_TOK(tok, lex, TOK_EXCLAM);
bool is_braced = (lex.lookahead(0) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN));
@@ -1469,6 +1517,102 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
return true;
}
+#if 0
+namespace {
+ ::AST::Module::FileInfo get_submod_file(
+ Span sp, const ::AST::Module::FileInfo& parent_fileinfo, const ::std::string& new_mod_name, const ::std::string& path_attr,
+ bool is_extern_file, bool is_cfg_disabled
+ )
+ {
+ ::AST::Module::FileInfo rv;
+ TRACE_FUNCTION_F(new_mod_name << ", " << path_attr << ", " << is_extern_file);
+ ::std::string sub_path;
+ bool sub_file_controls_dir = true;
+
+ // 1. Determine the base path for the module
+ if( parent_fileinfo.path == "-" ) {
+ if( path_attr.size() ) {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ sub_path = "-";
+ }
+ else if( path_attr.size() > 0 )
+ {
+ // #[path] present, add to the parent path
+ sub_path = dirname(parent_fileinfo.path) + path_attr;
+ }
+ else if( mod_fileinfo.controls_dir )
+ {
+ // The parent module is either the crate root, or a `mod.rs` (or otherwise a controller)
+ sub_path = parent_fileinfo.dir + name;
+ }
+ else
+ {
+ sub_path = parent_fileinfo.path;
+ sub_file_controls_dir = false;
+ }
+ DEBUG("Mod '" << name << "', sub_path = " << sub_path);
+
+ rv.path = sub_path;
+ rv.controls_dir = sub_file_controls_dir;
+
+ if( is_cfg_disabled || parent_fileinfo.force_no_load )
+ {
+ rv.force_no_load = true;
+ }
+ if( ! is_extern_file )
+ {
+ // If this is an inline module, set the path to just a directory
+ if( sub_path != "-" ) {
+ rv.path = sub_path + "/";
+ rv.dir = sub_path + "/";
+ }
+ else {
+ rv.path = "-";
+ }
+ }
+ else
+ {
+ if( sub_path == "-" )
+ {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ else
+ {
+ ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
+ DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
+ ::std::ifstream ifs_dir (newpath_dir + "mod.rs");
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_dir.is_open() && ifs_file.is_open() )
+ {
+ // Collision
+ ERROR(lex.point_span(), E0000, "Both modname.rs and modname/mod.rs exist");
+ }
+ else if( ifs_dir.is_open() )
+ {
+ // Load from dir
+ rv.path = newpath_dir + "mod.rs";
+ rv.dir = newpath_dir;
+ }
+ else if( ifs_file.is_open() )
+ {
+ rv.path = newpath_file;
+ rv.dir = newpath_dir;
+ rv.controls_dir = false;
+ }
+ else
+ {
+ // Can't find file
+ ERROR(sp, E0000, "Can't find file for '" << name << "' in '" << parent_fileinfo.dir << "'");
+ }
+ }
+ }
+ return rv;
+ }
+}
+#endif
+
::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items)
{
TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
@@ -1489,24 +1633,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
auto rv = tok.take_frag_item();
// Transfer new attributes onto the item
for(auto& mi : meta_items.m_items)
- rv.data.attrs.m_items.push_back( mv$(mi) );
+ rv.attrs.m_items.push_back( mv$(mi) );
return rv;
}
auto ps = lex.start_span();
- ::std::string item_name;
+ RcString item_name;
::AST::Item item_data;
{
::AST::MacroInvocation inv;
if( Parse_MacroInvocation_Opt(lex, inv) )
{
- item_data = ::AST::Item( mv$(inv) );
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), false, "", ::AST::Item( mv$(inv) ) };
}
}
@@ -1515,16 +1655,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_USE:
- // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement.
- // - These are caught by the condition in the closure
- Parse_Use(lex, [&](AST::UseStmt p, std::string s) {
- DEBUG(mod_path << " - use " << p << " as '" << s << "'");
- if( !item_data.is_None() )
- TODO(lex.point_span(), "Encode multi-item use statements as a single Item");
- item_data = ::AST::Item(mv$(p));
- item_name = mv$(s);
- });
- assert( !item_data.is_None() );
+ item_data = Parse_Use(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
break;
@@ -1540,7 +1671,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern "<ABI>" fn ...`
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
break; }
// `extern "ABI" {`
@@ -1555,7 +1686,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern fn ...`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
break;
@@ -1574,20 +1705,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern crate "crate-name" as crate_name;`
// NOTE: rustc doesn't allow this, keep in mrustc for for reparse support
case TOK_STRING:
- item_data = ::AST::Item::make_Crate({ tok.str() });
+ item_data = ::AST::Item::make_Crate({ RcString::new_interned(tok.str()) });
GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
break;
// `extern crate crate_name;`
// `extern crate crate_name as other_name;`
case TOK_IDENT:
- item_name = mv$(tok.str());
+ item_name = tok.istr();
if(GET_TOK(tok, lex) == TOK_RWORD_AS) {
item_data = ::AST::Item::make_Crate({ mv$(item_name) });
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1610,7 +1741,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
switch( GET_TOK(tok, lex) )
{
case TOK_IDENT: {
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1622,12 +1753,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
case TOK_RWORD_UNSAFE:
GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,true/*unsafe,const*/) );
break;
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
break;
@@ -1644,7 +1775,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
GET_TOK(tok, lex);
}
CHECK_TOK(tok, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1674,20 +1805,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, true,false/*unsafe,const*/) );
break; }
// `unsafe fn`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) );
break;
// `unsafe trait`
case TOK_RWORD_TRAIT: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
auto tr = Parse_TraitDef(lex, meta_items);
tr.set_is_unsafe();
item_data = ::AST::Item( ::std::move(tr) );
@@ -1704,8 +1835,21 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else {
BUG(lex.point_span(), "Parse_Impl returned a variant other than Impl or NegImpl");
}
- return ::AST::Named< ::AST::Item> { "", mv$(impl), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", mv$(impl) };
}
+ // `unsafe auto trait`
+ case TOK_IDENT:
+ if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ 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});
}
@@ -1713,65 +1857,142 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `fn`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,false/*unsafe,const*/) );
break;
// `type`
case TOK_RWORD_TYPE:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_TypeAlias(lex) );
break;
// `struct`
case TOK_RWORD_STRUCT:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_Struct(lex, meta_items) );
break;
// `enum`
case TOK_RWORD_ENUM:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
break;
// Contextual keywords
case TOK_IDENT:
- if( tok.str() == "union" ) {
+ if( tok.istr() == "union" ) {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_Union(lex, meta_items) );
}
+ // `auto trait`
+ else if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_marker();
+ item_data = ::AST::Item( ::std::move(tr) );
+ }
else {
throw ParseError::Unexpected(lex, tok);
}
break;
// `impl`
case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", Parse_Impl(lex, mv$(meta_items)) };
// `trait`
case TOK_RWORD_TRAIT:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
break;
+ case TOK_RWORD_MACRO:
+ if( TARGETVER_1_29 )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ if( lex.lookahead(0) != TOK_PAREN_OPEN )
+ {
+ GET_TOK(tok, lex);
+ throw ParseError::Unexpected(lex, tok);
+ }
+ DEBUG("name = " << name);
+
+ ::std::vector<RcString> names;
+ auto ps = lex.start_span();
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
+ auto pat_span = lex.end_span(ps);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ // TODO: Pass a flag that annotates all idents with the current module?
+ auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names);
+
+ auto mr = new MacroRules( );
+ mr->m_hygiene = lex.getHygiene();
+ {
+ Ident::ModPath mp;
+ for(const auto& node : mod_path.nodes())
+ {
+ mp.ents.push_back(node.name());
+ }
+ mr->m_hygiene.set_mod_path(::std::move(mp));
+ }
+ mr->m_rules.push_back(Parse_MacroRules_MakeArm(pat_span, ::std::move(arm_pat), ::std::move(body)));
+
+ item_name = name;
+ item_data = ::AST::Item( MacroRulesPtr(mr) );
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ break;
+
case TOK_RWORD_MOD: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
DEBUG("Sub module '" << name << "'");
AST::Module submod( mod_path + name );
+ // Check #[cfg] and don't load if it fails
+ struct H {
+ static bool check_item_cfg(const ::AST::AttributeList& attrs)
+ {
+ for(const auto& at : attrs.m_items) {
+ if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
// Rules for external files (/ path handling):
// - IF using stdin (path='-') - Disallow and propagate '-' as path
// - IF a #[path] attribute was passed, allow
// - IF in crate root or mod.rs, allow (input flag)
// - else, disallow and set flag
- ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : "");
+ ::std::string path_attr;
+ for(const auto& a : meta_items.m_items)
+ {
+ if( a.name() == "path" ) {
+ path_attr = a.string();
+ }
+ else if( a.name() == "cfg_attr" && a.items().at(1).name() == "path" ) {
+ if( check_cfg(a.span(), a.items().at(0)) ) {
+ path_attr = a.items().at(1).string();
+ }
+ }
+ else {
+ }
+ }
- //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
+ //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON, H::check_item_cfg(meta_items));
- ::std::string sub_path;
+ ::helpers::path sub_path;
bool sub_file_controls_dir = true;
if( mod_fileinfo.path == "-" ) {
if( path_attr.size() ) {
@@ -1781,15 +2002,16 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
else if( path_attr.size() > 0 )
{
- sub_path = dirname(mod_fileinfo.path) + path_attr;
+ sub_path = dirname(mod_fileinfo.path) / path_attr.c_str();
}
else if( mod_fileinfo.controls_dir )
{
- sub_path = dirname(mod_fileinfo.path) + name;
+ sub_path = dirname(mod_fileinfo.path) / name.c_str();
}
else
{
- sub_path = mod_fileinfo.path;
+ sub_path = dirname(mod_fileinfo.path) / mod_path.nodes().back().name().c_str() / name.c_str();
+ //sub_path = mod_fileinfo.path;
sub_file_controls_dir = false;
}
DEBUG("Mod '" << name << "', sub_path = " << sub_path);
@@ -1797,43 +2019,49 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
submod.m_file_info.path = sub_path;
submod.m_file_info.controls_dir = sub_file_controls_dir;
- // Check #[cfg] and don't load if it fails
- struct H {
- static bool check_item_cfg(const ::AST::AttributeList& attrs)
- {
- for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
- return false;
- }
- }
- return true;
- }
- };
-
switch( GET_TOK(tok, lex) )
{
case TOK_BRACE_OPEN:
- submod.m_file_info.path = sub_path + "/";
+ submod.m_file_info.path = sub_path.str() + "/";
+ // TODO: If cfg fails, just eat the TT until a matching #[cfg]?
+ // - Or, mark the file infor as not being valid (so child modules don't try to load)
Parse_ModRoot(lex, submod, meta_items);
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
break;
case TOK_SEMICOLON:
- if( sub_path == "-" ) {
+ if( sub_path.str() == "-" ) {
ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
}
- else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
- {
- ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
- }
else if( !H::check_item_cfg(meta_items) ) {
// Ignore - emit Item::None
item_name = mv$(name);
item_data = ::AST::Item( );
break ;
}
+ else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
+ {
+ // TODO: Also search for curmod/submod.rs
+ //::std::string newpath_file = (mod_path.nodes().size() > 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-2].name() + "/" + name + ".rs" : "");
+ ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) / mod_path.nodes()[mod_path.nodes().size()-1].name().c_str() / name.c_str() + ".rs" : "");
+ DEBUG("newpath_file = '" << newpath_file << "' " << mod_fileinfo.path << " " << mod_path);
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_file.is_open() )
+ {
+ submod.m_file_info.path = newpath_file;
+ submod.m_file_info.controls_dir = false;
+ DEBUG("- path = " << submod.m_file_info.path);
+ Lexer sub_lex(submod.m_file_info.path);
+ Parse_ModRoot(sub_lex, submod, meta_items);
+ GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
+ }
+ else
+ {
+ ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
+ }
+ }
else
{
- ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_dir = sub_path.str() + "/";
::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
::std::ifstream ifs_dir (newpath_dir + "mod.rs");
@@ -1851,7 +2079,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else if( ifs_file.is_open() )
{
submod.m_file_info.path = newpath_file;
+ if( path_attr == "" )
+ {
+ submod.m_file_info.controls_dir = false;
+ }
}
+ // TODO: If this is not a controlling file, look in `modname/` for the new module
else
{
// Can't find file
@@ -1874,10 +2107,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
throw ParseError::Unexpected(lex, tok);
}
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(item_name), mv$(item_data) };
}
void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items)
@@ -1885,26 +2115,7 @@ void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_
SET_MODULE(lex, mod);
lex.parse_state().parent_attrs = &meta_items;
- //TRACE_FUNCTION;
- Token tok;
-
- // `use ...`
- // TODO: This doesn't spot `pub(path) use`.
- if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
- {
- bool is_public = Parse_Publicity(lex);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_USE);
-
- Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) {
- DEBUG(mod.path() << " - use " << p << " as '" << s << "'");
- mod.add_alias(is_public, mv$(p), s, meta_items.clone());
- });
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- }
- else
- {
- mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
- }
+ mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
}
void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
@@ -1959,6 +2170,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 2e5a61d4..f9ecd028 100644
--- a/src/parse/token.cpp
+++ b/src/parse/token.cpp
@@ -35,6 +35,9 @@ Token::~Token()
case TOK_INTERPOLATED_META:
delete reinterpret_cast<AST::Attribute*>(m_data.as_Fragment());
break;
+ case TOK_INTERPOLATED_VIS:
+ delete reinterpret_cast<AST::Visibility*>(m_data.as_Fragment());
+ break;
default:
break;
}
@@ -49,6 +52,11 @@ Token::Token(enum eTokenType type):
m_type(type)
{
}
+Token::Token(enum eTokenType type, RcString str):
+ m_type(type),
+ m_data(Data::make_IString(mv$(str)))
+{
+}
Token::Token(enum eTokenType type, ::std::string str):
m_type(type),
m_data(Data::make_String(mv$(str)))
@@ -68,7 +76,12 @@ Token::Token(const InterpolatedFragment& frag)
{
switch(frag.m_type)
{
- case InterpolatedFragment::TT: throw "";
+ case InterpolatedFragment::TT:
+ throw "";
+ case InterpolatedFragment::VIS:
+ m_type = TOK_INTERPOLATED_VIS;
+ m_data = new AST::Visibility( *reinterpret_cast<const AST::Visibility*>(frag.m_ptr) );
+ break;
case InterpolatedFragment::TYPE:
m_type = TOK_INTERPOLATED_TYPE;
m_data = new TypeRef( reinterpret_cast<const TypeRef*>(frag.m_ptr)->clone() );
@@ -97,8 +110,8 @@ Token::Token(const InterpolatedFragment& frag)
case InterpolatedFragment::ITEM: {
m_type = TOK_INTERPOLATED_ITEM;
const auto& named = *reinterpret_cast<const AST::Named<AST::Item>*>(frag.m_ptr);
- ::AST::Item item = named.data.clone();
- m_data = new AST::Named<AST::Item>( named.name, mv$(item), named.is_pub );
+ auto item = named.data.clone();
+ m_data = new AST::Named<AST::Item>( named.span, named.attrs.clone(), named.is_pub, named.name, mv$(item) );
break; }
}
}
@@ -106,7 +119,12 @@ Token::Token(TagTakeIP, InterpolatedFragment frag)
{
switch(frag.m_type)
{
- case InterpolatedFragment::TT: throw "";
+ case InterpolatedFragment::TT:
+ throw "";
+ case InterpolatedFragment::VIS:
+ m_type = TOK_INTERPOLATED_VIS;
+ m_data = new AST::Visibility( mv$(*reinterpret_cast<AST::Visibility*>(frag.m_ptr)) );
+ break;
case InterpolatedFragment::TYPE:
m_type = TOK_INTERPOLATED_TYPE;
m_data = new TypeRef( mv$(*reinterpret_cast<TypeRef*>(frag.m_ptr)) );
@@ -150,6 +168,7 @@ Token::Token(const Token& t):
assert( t.m_data.tag() != Data::TAGDEAD );
TU_MATCH(Data, (t.m_data), (e),
(None, ),
+ (IString, m_data = Data::make_IString(e); ),
(String, m_data = Data::make_String(e); ),
(Integer, m_data = Data::make_Integer(e);),
(Float, m_data = Data::make_Float(e);),
@@ -165,6 +184,9 @@ Token Token::clone() const
TU_MATCH(Data, (m_data), (e),
(None,
),
+ (IString,
+ rv.m_data = Data::make_IString(e);
+ ),
(String,
rv.m_data = Data::make_String(e);
),
@@ -229,6 +251,15 @@ Token Token::clone() const
delete ptr;
return mv$(rv);
}
+::AST::Visibility Token::take_frag_vis()
+{
+ assert( m_type == TOK_INTERPOLATED_VIS );
+ auto ptr = reinterpret_cast<AST::Visibility*>(m_data.as_Fragment());
+ m_data.as_Fragment() = nullptr;
+ auto rv = mv$( *ptr );
+ delete ptr;
+ return mv$(rv);
+}
const char* Token::typestr(enum eTokenType type)
{
@@ -310,9 +341,10 @@ struct EscapedString {
case TOK_INTERPOLATED_META: return "/*:meta*/";
case TOK_INTERPOLATED_ITEM: return "/*:item*/";
case TOK_INTERPOLATED_IDENT: return "/*:ident*/";
+ case TOK_INTERPOLATED_VIS: return "/*:vis*/";
// Value tokens
- case TOK_IDENT: return m_data.as_String();
- case TOK_LIFETIME: return "'" + m_data.as_String();
+ case TOK_IDENT: return m_data.as_IString().c_str();
+ case TOK_LIFETIME: return FMT("'" << m_data.as_IString().c_str());
case TOK_INTEGER:
if( m_data.as_Integer().m_datatype == CORETYPE_ANY ) {
return FMT(m_data.as_Integer().m_intval);
@@ -360,8 +392,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 "+=";
@@ -454,6 +487,7 @@ struct EscapedString {
case TOK_RWORD_BE: return "be";
case TOK_RWORD_UNSIZED: return "unsized";
+ case TOK_RWORD_MACRO: return "macro";
}
throw ParseError::BugCheck("Reached end of Token::to_str");
}
@@ -485,13 +519,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/token.hpp b/src/parse/token.hpp
index 3605679b..0d9a8015 100644
--- a/src/parse/token.hpp
+++ b/src/parse/token.hpp
@@ -44,6 +44,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const Position& p);
class TypeRef;
class TokenTree;
namespace AST {
+ typedef bool Visibility;
class Pattern;
class Path;
class ExprNode;
@@ -63,6 +64,7 @@ class Token
TAGGED_UNION(Data, None,
(None, struct {}),
+ (IString, RcString),
(String, ::std::string),
(Integer, struct {
enum eCoreType m_datatype;
@@ -107,6 +109,7 @@ public:
Token(enum eTokenType type);
Token(enum eTokenType type, ::std::string str);
+ Token(enum eTokenType type, RcString str);
Token(uint64_t val, enum eCoreType datatype);
Token(double val, enum eCoreType datatype);
Token(const InterpolatedFragment& );
@@ -114,24 +117,28 @@ public:
Token(TagTakeIP, InterpolatedFragment );
enum eTokenType type() const { return m_type; }
+ const RcString& istr() const { return m_data.as_IString(); }
::std::string& str() { return m_data.as_String(); }
const ::std::string& str() const { return m_data.as_String(); }
enum eCoreType datatype() const { TU_MATCH_DEF(Data, (m_data), (e), (assert(!"Getting datatype of invalid token type");), (Integer, return e.m_datatype;), (Float, return e.m_datatype;)) throw ""; }
uint64_t intval() const { return m_data.as_Integer().m_intval; }
double floatval() const { return m_data.as_Float().m_floatval; }
+ // TODO: Replace these with a way of getting a InterpolatedFragment&
TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast<TypeRef*>( m_data.as_Fragment() ); }
AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast<AST::Path*>( m_data.as_Fragment() ); }
AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast<AST::Pattern*>( m_data.as_Fragment() ); }
AST::Attribute& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::Attribute*>( m_data.as_Fragment() ); }
::std::unique_ptr<AST::ExprNode> take_frag_node();
::AST::Named<AST::Item> take_frag_item();
+ ::AST::Visibility take_frag_vis();
bool operator==(const Token& r) const {
if(type() != r.type())
return false;
TU_MATCH(Data, (m_data, r.m_data), (e, re),
(None, return true;),
+ (IString, return e == re; ),
(String, return e == re; ),
(Integer, return e.m_datatype == re.m_datatype && e.m_intval == re.m_intval;),
(Float, return e.m_datatype == re.m_datatype && e.m_floatval == re.m_floatval;),
diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp
index 889c626c..6f0c57a1 100644
--- a/src/parse/tokenstream.cpp
+++ b/src/parse/tokenstream.cpp
@@ -138,11 +138,11 @@ Span TokenStream::point_span() const
Ident TokenStream::get_ident(Token tok) const
{
if(tok.type() == TOK_IDENT) {
- return Ident(getHygiene(), tok.str());
+ return Ident(getHygiene(), tok.istr());
}
else if(tok.type() == TOK_LIFETIME) {
// TODO: Maybe only when it's explicitly asked for?
- return Ident(getHygiene(), tok.str());
+ return Ident(getHygiene(), tok.istr());
}
else if( tok.type() == TOK_INTERPOLATED_IDENT ) {
TODO(getPosition(), "get_ident from TOK_INTERPOLATED_IDENT");
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 ca5b7892..979a8045 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 ===
@@ -61,7 +62,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_DOUBLE_LT: {
PUTBACK(tok, lex);
auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(path));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path));
}
//
case TOK_RWORD_FOR: {
@@ -82,7 +83,20 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
{
lex.getToken();
// TODO: path macros
- return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex));
+ return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, tok.istr(), lex));
+ }
+ if( TARGETVER_1_29 && tok.istr() == "dyn" )
+ {
+ if( lex.lookahead(0) == TOK_PAREN_OPEN ) {
+ GET_TOK(tok, lex);
+ auto rv = Parse_Type_TraitObject(lex, {});
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
+ return rv;
+ }
+ else {
+ ::AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex);
+ return Parse_Type_TraitObject(lex, mv$(hrbs));
+ }
}
// or a primitive
//if( auto ct = coretype_fromstring(tok.str()) )
@@ -122,7 +136,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
else {
PUTBACK(tok, lex);
}
- return TypeRef(TypeRef::TagReference(), lex.end_span(mv$(ps)), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagReference(), lex.end_span(ps), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
}
// '*' - Raw pointer
case TOK_STAR:
@@ -131,10 +145,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
{
case TOK_RWORD_MUT:
// Mutable pointer
- return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), true, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagPointer(), lex.end_span(ps), true, Parse_Type(lex, false));
case TOK_RWORD_CONST:
// Immutable pointer
- return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), false, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagPointer(), lex.end_span(ps), false, Parse_Type(lex, false));
default:
throw ParseError::Unexpected(lex, tok, {TOK_RWORD_CONST, TOK_RWORD_MUT});
}
@@ -147,11 +161,11 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
// Sized array
AST::Expr array_size = Parse_Expr(lex);
GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- return TypeRef(TypeRef::TagSizedArray(), lex.end_span(mv$(ps)), mv$(inner), array_size.take_node());
+ return TypeRef(TypeRef::TagSizedArray(), lex.end_span(ps), mv$(inner), array_size.take_node());
}
else if( tok.type() == TOK_SQUARE_CLOSE )
{
- return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(mv$(ps)), mv$(inner));
+ return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(ps), mv$(inner));
}
else {
throw ParseError::Unexpected(lex, tok/*, "; or ]"*/);
@@ -162,7 +176,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_PAREN_OPEN: {
DEBUG("Tuple");
if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), {});
+ return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), {});
PUTBACK(tok, lex);
TypeRef inner = Parse_Type(lex, true);
@@ -185,7 +199,8 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
types.push_back( Parse_Type(lex) );
}
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), mv$(types)); }
+ return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(types));
+ }
}
default:
throw ParseError::Unexpected(lex, tok);
@@ -259,7 +274,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs)
PUTBACK(tok, lex);
}
- return TypeRef(TypeRef::TagFunction(), lex.end_span(mv$(ps)), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
+ return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
}
TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list)
@@ -268,16 +283,17 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a
auto ps = lex.start_span();
+ auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
if( hrbs.empty() && !allow_trait_list )
{
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), Parse_Path(lex, PATH_GENERIC_TYPE));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path));
}
else
{
::std::vector<Type_TraitPath> traits;
::std::vector<AST::LifetimeRef> lifetimes;
- traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ traits.push_back(Type_TraitPath { mv$(hrbs), mv$(path) });
if( allow_trait_list )
{
@@ -303,38 +319,65 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a
{
if( lifetimes.empty())
lifetimes.push_back(AST::LifetimeRef());
- return TypeRef(lex.end_span(mv$(ps)), mv$(traits), mv$(lifetimes));
+ return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes));
}
else
{
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(traits.at(0).path));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(traits.at(0).path));
}
}
}
-TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
+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;
- do {
+ ::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
{
- AST::HigherRankedBounds hrbs;
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;
+
+ auto ps = lex.start_span();
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
+ do {
+ if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
+ GET_TOK(tok, lex);
+ lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
+ }
+ else
+ {
+ AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex);
+ traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ }
} while( GET_TOK(tok, lex) == TOK_PLUS );
PUTBACK(tok, lex);
- return TypeRef(lex.end_span(mv$(ps)), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
+ return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
}
diff --git a/src/rc_string.cpp b/src/rc_string.cpp
index 4025d8c8..b56f2e62 100644
--- a/src/rc_string.cpp
+++ b/src/rc_string.cpp
@@ -7,17 +7,19 @@
*/
#include <rc_string.hpp>
#include <cstring>
+#include <string>
#include <iostream>
+#include <algorithm> // std::max
RcString::RcString(const char* s, unsigned int len):
- m_ptr(nullptr),
- m_len(len)
+ m_ptr(nullptr)
{
if( len > 0 )
{
- m_ptr = new unsigned int[1 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)];
- *m_ptr = 1;
- char* data_mut = reinterpret_cast<char*>(m_ptr + 1);
+ m_ptr = new unsigned int[2 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)];
+ m_ptr[0] = 1;
+ m_ptr[1] = len;
+ char* data_mut = reinterpret_cast<char*>(m_ptr + 2);
for(unsigned int j = 0; j < len; j ++ )
data_mut[j] = s[j];
data_mut[len] = '\0';
@@ -25,16 +27,6 @@ RcString::RcString(const char* s, unsigned int len):
//::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " (creation)" << ::std::endl;
}
}
-RcString::RcString(const RcString& x):
- m_ptr(x.m_ptr),
- m_len(x.m_len)
-{
- if( m_ptr )
- {
- *m_ptr += 1;
- //::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " refs present (copy)" << ::std::endl;
- }
-}
RcString::~RcString()
{
if(m_ptr)
@@ -48,14 +40,87 @@ RcString::~RcString()
}
}
}
-bool RcString::operator==(const char* s) const
+Ordering RcString::ord(const char* s, size_t len) const
+{
+ if( m_ptr == nullptr )
+ return (len == 0 ? OrdEqual : OrdLess);
+ if( len == 0 )
+ return OrdGreater;
+
+ assert(this->size() > 0);
+ assert(len > 0);
+
+ int cmp = memcmp(this->c_str(), s, ::std::min(len, this->size()));
+ if(cmp == 0)
+ return ::ord(this->size(), len);
+ return ::ord(cmp, 0);
+}
+Ordering RcString::ord(const char* s) const
+{
+ if( m_ptr == nullptr )
+ return (*s == '\0' ? OrdEqual : OrdLess);
+
+ int cmp = strncmp(this->c_str(), s, this->size());
+ if( cmp == 0 )
+ {
+ if( s[this->size()] == '\0' )
+ return OrdEqual;
+ else
+ return OrdLess;
+ }
+ return ::ord(cmp, 0);
+}
+
+::std::ostream& operator<<(::std::ostream& os, const RcString& x)
{
- if( m_len == 0 )
- return *s == '\0';
- auto m = this->c_str();
- do {
- if( *m != *s )
- return false;
- } while( *m++ != '\0' && *s++ != '\0' );
- return true;
+ for(size_t i = 0; i < x.size(); i ++)
+ {
+ os << x.c_str()[i];
+ }
+ return os;
+}
+
+
+::std::set<RcString> RcString_interned_strings;
+
+RcString RcString::new_interned(const ::std::string& s)
+{
+#if 0
+ auto it = RcString_interned_strings.find(s);
+ if( it == RcString_interned_strings.end() )
+ {
+ it = RcString_interned_strings.insert(RcString(s)).first;
+ }
+ return *it;
+#else
+ // TODO: interning flag, so comparisons can just be a pointer comparison
+ // - Only want to set this flag on the cached instance
+ return *RcString_interned_strings.insert(RcString(s)).first;
+#endif
+}
+RcString RcString::new_interned(const char* s)
+{
+#if 0
+ auto it = RcString_interned_strings.find(s);
+ if( it == RcString_interned_strings.end() )
+ {
+ it = RcString_interned_strings.insert(RcString(s)).first;
+ }
+ return *it;
+#else
+ // TODO: interning flag, so comparisons can just be a pointer comparison
+ // - Only want to set this flag on the cached instance
+ return *RcString_interned_strings.insert(RcString(s)).first;
+#endif
+}
+
+size_t std::hash<RcString>::operator()(const RcString& s) const noexcept
+{
+ // http://www.cse.yorku.ca/~oz/hash.html "djb2"
+ size_t h = 5381;
+ for(auto c : s) {
+ h = h * 33 + (unsigned)c;
+ }
+ return h;
+ //return hash<std::string_view>(s.c_str(), s.size());
}
diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp
index 19da5820..86bc47c7 100644
--- a/src/resolve/absolute.cpp
+++ b/src/resolve/absolute.cpp
@@ -41,7 +41,7 @@ namespace
template<typename Val>
struct Named
{
- ::std::string name;
+ RcString name;
Val value;
};
template<typename Val>
@@ -65,6 +65,9 @@ namespace
}),
(Generic, struct {
// Map of names to slots
+ GenericSlot::Level level;
+ ::AST::GenericParams* params_def; // TODO: What if it's HRBs?, they have a different type
+ //::AST::HigherRankedBounds* hrbs_def;
::std::vector< Named< GenericSlot > > types;
::std::vector< Named< GenericSlot > > constants;
::std::vector< NamedI< GenericSlot > > lifetimes;
@@ -78,16 +81,20 @@ namespace
unsigned int m_block_level;
bool m_frozen_bind_set;
+ // Destination `GenericParams` for in_band_lifetimes
+ ::AST::GenericParams* m_ibl_target_generics;
+
Context(const ::AST::Crate& crate, const ::AST::Module& mod):
m_crate(crate),
m_mod(mod),
m_var_count(~0u),
m_block_level(0),
- m_frozen_bind_set( false )
+ m_frozen_bind_set( false ),
+ m_ibl_target_generics(nullptr)
{}
void push(const ::AST::HigherRankedBounds& params) {
- auto e = Ent::make_Generic({});
+ auto e = Ent::make_Generic({ GenericSlot::Level::Hrb, nullptr /*, &params*/ });
auto& data = e.as_Generic();
for(size_t i = 0; i < params.m_lifetimes.size(); i ++)
@@ -97,8 +104,8 @@ namespace
m_name_context.push_back(mv$(e));
}
- void push(const ::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) {
- auto e = Ent::make_Generic({});
+ void push(/*const */::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) {
+ auto e = Ent::make_Generic({ level, &params });
auto& data = e.as_Generic();
if( has_self ) {
@@ -279,6 +286,7 @@ namespace
Type,
Constant,
PatternValue,
+ //PatternAny,
Variable,
};
static const char* lookup_mode_msg(LookupMode mode) {
@@ -292,7 +300,7 @@ namespace
}
return "";
}
- AST::Path lookup(const Span& sp, const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const {
+ AST::Path lookup(const Span& sp, const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const {
auto rv = this->lookup_opt(name, src_context, mode);
if( !rv.is_valid() ) {
switch(mode)
@@ -306,13 +314,14 @@ namespace
}
return rv;
}
- static bool lookup_in_mod(const ::AST::Module& mod, const ::std::string& name, LookupMode mode, ::AST::Path& path) {
+ static bool lookup_in_mod(const ::AST::Module& mod, const RcString& name, LookupMode mode, ::AST::Path& path) {
switch(mode)
{
case LookupMode::Namespace:
{
auto v = mod.m_namespace_items.find(name);
if( v != mod.m_namespace_items.end() ) {
+ DEBUG("- NS: Namespace " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -320,6 +329,7 @@ namespace
{
auto v = mod.m_type_items.find(name);
if( v != mod.m_type_items.end() ) {
+ DEBUG("- NS: Type " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -327,32 +337,59 @@ namespace
break;
case LookupMode::Type:
- //if( name == "IntoIterator" ) {
- // DEBUG("lookup_in_mod(mod="<<mod.path()<<")");
- // for(const auto& v : mod.m_type_items) {
- // DEBUG("- " << v.first << " = " << (v.second.is_pub ? "pub " : "") << v.second.path);
- // }
- //}
{
auto v = mod.m_type_items.find(name);
if( v != mod.m_type_items.end() ) {
+ DEBUG("- TY: Type " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
}
+ // HACK: For `Enum::Var { .. }` patterns matching value variants
+ {
+ auto v = mod.m_value_items.find(name);
+ if( v != mod.m_value_items.end() ) {
+ const auto& b = v->second.path.m_bindings.value;
+ if( /*const auto* be =*/ b.opt_EnumVar() ) {
+ DEBUG("- TY: Enum variant " << v->second.path);
+ path = ::AST::Path( v->second.path );
+ return true;
+ }
+ }
+ }
break;
+ //case LookupMode::PatternAny:
+ // {
+ // auto v = mod.m_type_items.find(name);
+ // if( v != mod.m_type_items.end() ) {
+ // DEBUG("- TY: Type " << v->second.path);
+ // path = ::AST::Path( v->second.path );
+ // return true;
+ // }
+ // auto v2 = mod.m_value_items.find(name);
+ // if( v2 != mod.m_value_items.end() ) {
+ // const auto& b = v2->second.path.m_bindings.value;
+ // if( b.is_EnumVar() ) {
+ // DEBUG("- TY: Enum variant " << v2->second.path);
+ // path = ::AST::Path( v2->second.path );
+ // return true;
+ // }
+ // }
+ // }
+ // break;
case LookupMode::PatternValue:
{
auto v = mod.m_value_items.find(name);
if( v != mod.m_value_items.end() ) {
- const auto& b = v->second.path.binding();
+ const auto& b = v->second.path.m_bindings.value;
switch( b.tag() )
{
- case ::AST::PathBinding::TAG_EnumVar:
- case ::AST::PathBinding::TAG_Static:
+ case ::AST::PathBinding_Value::TAG_EnumVar:
+ case ::AST::PathBinding_Value::TAG_Static:
+ DEBUG("- PV: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
- case ::AST::PathBinding::TAG_Struct:
+ case ::AST::PathBinding_Value::TAG_Struct:
// TODO: Restrict this to unit-like structs
if( b.as_Struct().struct_ && !b.as_Struct().struct_->m_data.is_Unit() )
;
@@ -360,6 +397,7 @@ namespace
;
else
{
+ DEBUG("- PV: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -375,6 +413,7 @@ namespace
{
auto v = mod.m_value_items.find(name);
if( v != mod.m_value_items.end() ) {
+ DEBUG("- C/V: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -383,8 +422,31 @@ namespace
}
return false;
}
- AST::Path lookup_opt(const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const {
+ AST::Path lookup_opt(const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const {
DEBUG("name=" << name <<", src_context=" << src_context);
+ // NOTE: src_context may provide a module to search
+ if( src_context.has_mod_path() )
+ {
+ DEBUG(src_context.mod_path().ents);
+ const AST::Module* mod = &m_crate.root_module();
+ for(const auto& node : src_context.mod_path().ents)
+ {
+ const AST::Module* next = nullptr;
+ for(const auto& i : mod->items())
+ {
+ if( i.name == node ) {
+ next = &i.data.as_Module();
+ break;
+ }
+ }
+ assert(next);
+ mod = next;
+ }
+ ::AST::Path rv;
+ if( this->lookup_in_mod(*mod, name, mode, rv) ) {
+ return rv;
+ }
+ }
for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it)
{
TU_MATCH(Ent, (*it), (e),
@@ -451,7 +513,7 @@ namespace
case LookupMode::Namespace:
case LookupMode::Type: {
// Look up primitive types
- auto ct = coretype_fromstring(name);
+ auto ct = coretype_fromstring(name.c_str());
if( ct != CORETYPE_INVAL )
{
return ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() );
@@ -461,10 +523,22 @@ namespace
break;
}
+ // #![feature(extern_prelude)] - 2018-style extern paths
+ if( mode == LookupMode::Namespace && TARGETVER_1_29 && true /*m_crate.has_feature("extern_prelude")*/ )
+ {
+ DEBUG("Extern crates - " << FMT_CB(os, for(const auto& v: m_crate.m_extern_crates) os << v.first << ":" << v.second.m_short_name <<",";));
+ auto it = ::std::find_if(m_crate.m_extern_crates.begin(), m_crate.m_extern_crates.end(), [&](const auto& x){ return x.second.m_short_name == name; });
+ if( it != m_crate.m_extern_crates.end() )
+ {
+ DEBUG("- Found '" << name << "'");
+ return AST::Path(it->first, {});
+ }
+ }
+
return AST::Path();
}
- unsigned int lookup_local(const Span& sp, const ::std::string name, LookupMode mode) {
+ unsigned int lookup_local(const Span& sp, const RcString name, LookupMode mode) {
for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it)
{
TU_MATCH(Ent, (*it), (e),
@@ -544,6 +618,10 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn);
void Resolve_Absolute_PathParams(/*const*/ Context& context, const Span& sp, ::AST::PathParams& args)
{
+ for(auto& arg : args.m_lifetimes)
+ {
+ Resolve_Absolute_Lifetime(context, sp, arg);
+ }
for(auto& arg : args.m_types)
{
Resolve_Absolute_Type(context, arg);
@@ -592,7 +670,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L
{
// Trait is specified, definitely a trait item
// - Must resolve here
- const auto& pb = ufcs.trait->binding();
+ const auto& pb = ufcs.trait->m_bindings.type;
if( ! pb.is_Trait() ) {
ERROR(sp, E0000, "UFCS trait was not a trait - " << *ufcs.trait);
}
@@ -654,7 +732,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L
}
namespace {
- AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const ::std::string& crate_name)
+ AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const RcString& crate_name)
{
auto& nodes = path.nodes();
AST::Path np = AST::Path(crate_name, {});
@@ -662,10 +740,10 @@ namespace {
{
np.nodes().push_back( mv$(nodes[i]) );
}
- np.bind( path.binding().clone() );
+ np.m_bindings = path.m_bindings.clone();
return np;
}
- AST::Path split_into_ufcs_ty(const Span& sp, AST::Path path, unsigned int i /*item_name_idx*/)
+ AST::Path split_into_ufcs_ty(const Span& sp, const AST::Path& path, unsigned int i /*item_name_idx*/)
{
const auto& path_abs = path.m_class.as_Absolute();
auto type_path = ::AST::Path( path );
@@ -675,6 +753,8 @@ namespace {
for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ )
new_path.nodes().push_back( mv$(path_abs.nodes[j]) );
+ DEBUG(path << " -> " << new_path);
+
return new_path;
}
AST::Path split_replace_into_ufcs_path(const Span& sp, AST::Path path, unsigned int i, const AST::Path& ty_path_tpl)
@@ -716,7 +796,6 @@ namespace {
const auto& varname = p.m_components.back();
auto var_idx = e.find_variant(varname);
ASSERT_BUG(sp, var_idx != SIZE_MAX, "Extern crate import path points to non-present variant - " << p);
- auto pb = ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
// Construct output path (with same set of parameters)
AST::Path rv( p.m_crate_name, {} );
@@ -724,7 +803,12 @@ namespace {
for(const auto& c : p.m_components)
rv.nodes().push_back( AST::PathNode(c) );
rv.nodes().back().args() = mv$( path.nodes().back().args() );
- rv.bind( mv$(pb) );
+ if( e.m_data.is_Data() && e.m_data.as_Data()[var_idx].is_struct ) {
+ rv.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
+ }
+ else {
+ rv.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
+ }
path = mv$(rv);
return ;
@@ -735,7 +819,7 @@ namespace {
)
}
- ::AST::PathBinding pb;
+ ::AST::Path::Bindings pb;
const auto& name = p.m_components.back();
if( is_value )
@@ -749,19 +833,19 @@ namespace {
BUG(sp, "HIR Import item pointed to an import");
),
(Constant,
- pb = ::AST::PathBinding::make_Static({nullptr, nullptr});
+ pb.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
),
(Static,
- pb = ::AST::PathBinding::make_Static({nullptr, &e});
+ pb.value = ::AST::PathBinding_Value::make_Static({nullptr, &e});
),
(StructConstant,
- pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
+ pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
),
(Function,
- pb = ::AST::PathBinding::make_Function({nullptr/*, &e*/});
+ pb.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/});
),
(StructConstructor,
- pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
+ pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
)
)
}
@@ -776,22 +860,25 @@ namespace {
BUG(sp, "HIR Import item pointed to an import");
),
(Module,
- pb = ::AST::PathBinding::make_Module({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
),
(Trait,
- pb = ::AST::PathBinding::make_Trait({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(TypeAlias,
- pb = ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/});
+ pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
+ ),
+ (ExternType,
+ pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(Struct,
- pb = ::AST::PathBinding::make_Struct({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- pb = ::AST::PathBinding::make_Union({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
),
(Enum,
- pb = ::AST::PathBinding::make_Enum({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
)
)
}
@@ -802,7 +889,7 @@ namespace {
for(const auto& c : p.m_components)
rv.nodes().push_back( AST::PathNode(c) );
rv.nodes().back().args() = mv$( path.nodes().back().args() );
- rv.bind( mv$(pb) );
+ rv.m_bindings = mv$(pb);
path = mv$(rv);
}
@@ -816,7 +903,7 @@ namespace {
switch(mode)
{
case Context::LookupMode::Namespace:
- path.bind( ::AST::PathBinding::make_Module({nullptr, &crate.m_hir->m_root_module}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &crate.m_hir->m_root_module});
return ;
default:
TODO(sp, "Looking up a non-namespace, but pointed to crate root");
@@ -832,23 +919,30 @@ namespace {
if( it == hmod->m_mod_items.end() )
ERROR(sp, E0000, "Couldn't find path component '" << n.name() << "' of " << path);
- TU_MATCH(::HIR::TypeItem, (it->second->ent), (e),
- (Import,
+ TU_MATCH_HDRA( (it->second->ent), {)
+ TU_ARMA(Import, e) {
// - Update path then restart
auto newpath = AST::Path(e.path.m_crate_name, {});
for(const auto& n : e.path.m_components)
newpath.nodes().push_back( AST::PathNode(n) );
+ if( newpath.nodes().empty() ) {
+ ASSERT_BUG(sp, n.args().is_empty(), "Params present, but name resolves to a crate root - " << path << " #" << i << " -> " << newpath);
+ }
+ else {
+ newpath.nodes().back().args() = mv$(path.nodes()[i].args());
+ }
for(unsigned int j = i + 1; j < path.nodes().size(); j ++)
newpath.nodes().push_back( mv$(path.nodes()[j]) );
+ DEBUG("> Recurse with " << newpath);
path = mv$(newpath);
// TODO: Recursion limit
Resolve_Absolute_Path_BindAbsolute(context, sp, mode, path);
return ;
- ),
- (Module,
+ }
+ TU_ARMA(Module, e) {
hmod = &e;
- ),
- (Trait,
+ }
+ TU_ARMA(Trait, e) {
auto trait_path = ::AST::Path( crate.m_name, {} );
for(unsigned int j = start; j <= i; j ++)
trait_path.nodes().push_back( path_abs.nodes[j].name() );
@@ -862,7 +956,7 @@ namespace {
trait_path.nodes().back().args().m_types.push_back( ::TypeRef(sp) );
}
}
- trait_path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ trait_path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
::AST::Path new_path;
const auto& next_node = path_abs.nodes[i+1];
@@ -892,23 +986,15 @@ namespace {
path = mv$(new_path);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (TypeAlias,
- path = split_into_crate(sp, mv$(path), start, crate.m_name);
- path = split_into_ufcs_ty(sp, mv$(path), i-start);
- return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Struct,
- path = split_into_crate(sp, mv$(path), start, crate.m_name);
- path = split_into_ufcs_ty(sp, mv$(path), i-start);
- return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Union,
+ }
+ case ::HIR::TypeItem::TAG_ExternType:
+ case ::HIR::TypeItem::TAG_TypeAlias:
+ case ::HIR::TypeItem::TAG_Struct:
+ case ::HIR::TypeItem::TAG_Union:
path = split_into_crate(sp, mv$(path), start, crate.m_name);
path = split_into_ufcs_ty(sp, mv$(path), i-start);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Enum,
+ TU_ARMA(Enum, e) {
const auto& last_node = path_abs.nodes.back();
// If this refers to an enum variant, return the full path
auto idx = e.find_variant(last_node.name());
@@ -922,15 +1008,20 @@ namespace {
ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)");
}
- path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e}) );
+ if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) {
+ path.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e});
+ }
+ else {
+ path.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e});
+ }
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return;
}
path = split_into_crate(sp, mv$(path), start, crate.m_name);
path = split_into_ufcs_ty(sp, mv$(path), i-start);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- )
- )
+ }
+ }
}
const auto& name = path_abs.nodes.back().name();
@@ -949,22 +1040,25 @@ namespace {
return ;
),
(Trait,
- path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(Module,
- path.bind( ::AST::PathBinding::make_Module({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
+ ),
+ (ExternType,
+ path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(TypeAlias,
- path.bind( ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(Enum,
- path.bind( ::AST::PathBinding::make_Enum({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
),
(Struct,
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- path.bind( ::AST::PathBinding::make_Union({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
)
)
// Update path (trim down to `start` and set crate name)
@@ -984,7 +1078,7 @@ namespace {
),
(StructConstant,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return ;
),
@@ -994,7 +1088,7 @@ namespace {
),
(Constant,
// Bind and update path
- path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return ;
)
@@ -1016,22 +1110,22 @@ namespace {
return ;
),
(Function,
- path.bind( ::AST::PathBinding::make_Function({nullptr/*, &e*/}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/});
),
(StructConstructor,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
),
(StructConstant,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
),
(Static,
- path.bind( ::AST::PathBinding::make_Static({nullptr, &e}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, &e});
),
(Constant,
// Bind
- path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
)
)
path = split_into_crate(sp, mv$(path), start, crate.m_name);
@@ -1061,7 +1155,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
{
auto& n = path_abs.nodes[i];
- if( n.name()[0] == '#' ) {
+ if( n.name().c_str()[0] == '#' ) {
if( ! n.args().is_empty() ) {
ERROR(sp, E0000, "Type parameters were not expected here");
}
@@ -1072,7 +1166,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
char c;
unsigned int idx;
- ::std::stringstream ss( n.name() );
+ ::std::stringstream ss( n.name().c_str() );
ss >> c;
ss >> idx;
assert( idx < mod->anon_mods().size() );
@@ -1088,7 +1182,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
const auto& name_ref = it->second;
DEBUG("#" << i << " \"" << n.name() << "\" = " << name_ref.path << (name_ref.is_import ? " (import)" : "") );
- TU_MATCH_DEF(::AST::PathBinding, (name_ref.path.binding()), (e),
+ TU_MATCH_DEF(::AST::PathBinding_Type, (name_ref.path.m_bindings.type), (e),
(
ERROR(sp, E0000, "Encountered non-namespace item '" << n.name() << "' ("<<name_ref.path<<") in path " << path);
),
@@ -1235,7 +1329,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
if( ! Context::lookup_in_mod(*mod, path_abs.nodes.back().name(), mode, tmp) ) {
ERROR(sp, E0000, "Couldn't find " << Context::lookup_mode_msg(mode) << " '" << path_abs.nodes.back().name() << "' of " << path);
}
- assert( ! tmp.binding().is_Unbound() );
+ ASSERT_BUG(sp, tmp.m_bindings.has_binding(), "Lookup for " << path << " succeeded, but had no binding");
// Replaces the path with the one returned by `lookup_in_mod`, ensuring that `use` aliases are eliminated
DEBUG("Replace " << path << " with " << tmp);
@@ -1282,8 +1376,9 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
// HACK: If this is a primitive name, and resolved to a module.
// - If the next component isn't found in the located module
// > Instead use the type name.
- if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name()) != CORETYPE_INVAL ) {
- TU_IFLET( ::AST::PathBinding, p.binding(), Module, pe,
+ if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name().c_str()) != CORETYPE_INVAL ) {
+ if( const auto* pep = p.m_bindings.type.opt_Module() ) {
+ const auto& pe = *pep;
bool found = false;
const auto& name = e.nodes[1].name();
if( !pe.module_ ) {
@@ -1335,12 +1430,12 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
}
if( !found )
{
- auto ct = coretype_fromstring(e.nodes[0].name());
+ auto ct = coretype_fromstring(e.nodes[0].name().c_str());
p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() );
}
DEBUG("Primitive module hack yeilded " << p);
- )
+ }
}
if( e.nodes.size() > 1 )
@@ -1381,7 +1476,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
const auto& mp_nodes = context.m_mod.path().nodes();
// Ignore any leading anon modules
unsigned int start_len = mp_nodes.size();
- while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' )
+ while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' )
start_len --;
// - Create a new path
@@ -1405,7 +1500,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
assert( e.count >= 1 );
// TODO: The first super should ignore any anon modules.
unsigned int start_len = e.count > mp_nodes.size() ? 0 : mp_nodes.size() - e.count;
- while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' )
+ while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' )
start_len --;
// - Create a new path
@@ -1447,7 +1542,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
BUG(sp, "Path wasn't absolutised correctly");
),
(Local,
- if( path.binding().is_Unbound() )
+ if( !path.m_bindings.has_binding() )
{
TODO(sp, "Bind unbound local path - " << path);
}
@@ -1475,6 +1570,17 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe
return ;
}
+ if( lft.name() == "_" )
+ {
+ if( TARGETVER_1_19 )
+ {
+ ERROR(sp, E0000, "'_ is not a valid lifetime name in 1.19 mode");
+ }
+ // Note: '_ is just an explicit elided lifetime
+ lft.set_binding(AST::LifetimeRef::BINDING_INFER);
+ return ;
+ }
+
for(auto it = context.m_name_context.rbegin(); it != context.m_name_context.rend(); ++ it)
{
if( const auto* e = it->opt_Generic() )
@@ -1491,6 +1597,39 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe
}
}
+ if( TARGETVER_1_29 )
+ {
+ // If parsing a function header, add a new lifetime param to the function
+ // - Does the same apply to impl headers? Yes it does.
+ if( context.m_ibl_target_generics )
+ {
+ DEBUG("Considering in-band-lifetimes");
+ ASSERT_BUG(sp, !context.m_name_context.empty(), "Name context stack is empty");
+ auto it = context.m_name_context.rbegin();
+ ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str());
+ while( it->as_Generic().level == GenericSlot::Level::Hrb ) {
+ it ++;
+ ASSERT_BUG(sp, it != context.m_name_context.rend(), "");
+ ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str());
+ }
+ if( it->as_Generic().level != GenericSlot::Level::Hrb )
+ {
+ auto& context_gen = it->as_Generic();
+ auto& def_gen = *context.m_ibl_target_generics;
+ auto level = context_gen.level;
+ // 1. Assert that the last item of `context.m_name_context` is Generic, and matches `m_ibl_target_generics`
+ ASSERT_BUG(sp, context_gen.lifetimes.size() == def_gen.lft_params().size(), "");
+ ASSERT_BUG(sp, context_gen.types.size() == def_gen.ty_params().size(), "");
+ //ASSERT_BUG(sp, context_gen.constants.size() == def_gen.val_params().size(), "");
+ // 2. Add the new lifetime to both `m_ibl_target_generics` and the last entry in m_name_context
+ size_t idx = def_gen.lft_params().size();
+ def_gen.add_lft_param(AST::LifetimeParam(sp, {}, lft.name()));
+ context_gen.lifetimes.push_back( NamedI<GenericSlot> { lft.name(), GenericSlot { level, static_cast<unsigned short>(idx) } } );
+ lft.set_binding( idx | (static_cast<int>(level) << 8) );
+ return ;
+ }
+ }
+ }
ERROR(sp, E0000, "Couldn't find lifetime " << lft);
}
}
@@ -1565,7 +1704,7 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type)
assert( ufcs.nodes.size() == 1);
)
- TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be,
+ TU_IFLET(::AST::PathBinding_Type, e.path.m_bindings.type, Trait, be,
auto ty = ::TypeRef( type.span(), ::make_vec1(Type_TraitPath { {}, mv$(e.path)}), {} );
type = mv$(ty);
return ;
@@ -1865,6 +2004,10 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa
Resolve_Absolute_Pattern(context, allow_refutable, sp);
),
(Struct,
+ // TODO: `Struct { .. }` patterns can match anything
+ //if( e.sub_patterns.empty() && !e.is_exhaustive ) {
+ // auto rv = this->lookup_opt(name, src_context, mode);
+ //}
Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::Type, e.path);
for(auto& sp : e.sub_patterns)
Resolve_Absolute_Pattern(context, allow_refutable, sp.second);
@@ -1895,17 +2038,20 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST:
{
TU_MATCH(AST::Item, (i.data), (e),
(None, ),
- (MacroInv, BUG(i.data.span, "Resolve_Absolute_ImplItems - MacroInv");),
- (ExternBlock, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (Impl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (NegImpl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (Use, BUG(i.data.span, "Resolve_Absolute_ImplItems - Use");),
- (Module, BUG(i.data.span, "Resolve_Absolute_ImplItems - Module");),
- (Crate , BUG(i.data.span, "Resolve_Absolute_ImplItems - Crate");),
- (Enum , BUG(i.data.span, "Resolve_Absolute_ImplItems - Enum");),
- (Trait , BUG(i.data.span, "Resolve_Absolute_ImplItems - Trait");),
- (Struct, BUG(i.data.span, "Resolve_Absolute_ImplItems - Struct");),
- (Union , BUG(i.data.span, "Resolve_Absolute_ImplItems - Union");),
+ (MacroInv,
+ //BUG(i.span, "Resolve_Absolute_ImplItems - MacroInv");
+ ),
+ (ExternBlock, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Impl, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (NegImpl, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Macro, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Use, BUG(i.span, "Resolve_Absolute_ImplItems - Use");),
+ (Module, BUG(i.span, "Resolve_Absolute_ImplItems - Module");),
+ (Crate , BUG(i.span, "Resolve_Absolute_ImplItems - Crate");),
+ (Enum , BUG(i.span, "Resolve_Absolute_ImplItems - Enum");),
+ (Trait , BUG(i.span, "Resolve_Absolute_ImplItems - Trait");),
+ (Struct, BUG(i.span, "Resolve_Absolute_ImplItems - Struct");),
+ (Union , BUG(i.span, "Resolve_Absolute_ImplItems - Union");),
(Type,
DEBUG("Type - " << i.name);
assert( e.params().ty_params().size() == 0 );
@@ -1919,26 +2065,7 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST:
),
(Function,
DEBUG("Function - " << i.name);
- item_context.push( e.params(), GenericSlot::Level::Method );
- Resolve_Absolute_Generic(item_context, e.params());
-
- Resolve_Absolute_Type( item_context, e.rettype() );
- for(auto& arg : e.args())
- Resolve_Absolute_Type( item_context, arg.second );
-
- {
- auto _h = item_context.enter_rootblock();
- item_context.push_block();
- for(auto& arg : e.args()) {
- Resolve_Absolute_Pattern( item_context, false, arg.first );
- }
-
- Resolve_Absolute_Expr( item_context, e.code() );
-
- item_context.pop_block();
- }
-
- item_context.pop( e.params() );
+ Resolve_Absolute_Function(item_context, e);
),
(Static,
DEBUG("Static - " << i.name);
@@ -1959,16 +2086,17 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::std::vector< ::AST::Im
(None, ),
(MacroInv, ),
- (Impl , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (NegImpl, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (ExternBlock, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Use , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Module, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Crate , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Enum , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Trait , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Struct, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Union , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Impl , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (NegImpl, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (ExternBlock, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Macro , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Use , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Module, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Crate , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Enum , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Trait , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Struct, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Union , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
(Type,
DEBUG("Type - " << i.name);
assert( e.params().ty_params().size() == 0 );
@@ -1997,12 +2125,17 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn)
{
TRACE_FUNCTION_F("");
item_context.push( fcn.params(), GenericSlot::Level::Method );
+ item_context.m_ibl_target_generics = &fcn.params();
+ DEBUG("- Generics");
Resolve_Absolute_Generic(item_context, fcn.params());
+ DEBUG("- Prototype types");
Resolve_Absolute_Type( item_context, fcn.rettype() );
for(auto& arg : fcn.args())
Resolve_Absolute_Type( item_context, arg.second );
+ item_context.m_ibl_target_generics = nullptr;
+ DEBUG("- Body");
{
auto _h = item_context.enter_rootblock();
item_context.push_block();
@@ -2122,12 +2255,14 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(Use,
),
+ (Macro,
+ ),
(ExternBlock,
for(auto& i2 : e.items())
{
TU_MATCH_DEF(AST::Item, (i2.data), (e2),
(
- BUG(i2.data.span, "Unexpected item in ExternBlock - " << i2.data.tag_str());
+ BUG(i.span, "Unexpected item in ExternBlock - " << i2.data.tag_str());
),
(None,
),
@@ -2142,33 +2277,40 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(Impl,
auto& def = e.def();
- DEBUG("impl " << def.trait().ent << " for " << def.type());
if( !def.type().is_valid() )
{
- DEBUG("---- MARKER IMPL for " << def.trait().ent);
+ TRACE_FUNCTION_F("impl " << def.trait().ent << " for ..");
item_context.push(def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, def.params());
+
+ item_context.m_ibl_target_generics = &def.params();
assert( def.trait().ent.is_valid() );
Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent);
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, def.params());
if( e.items().size() != 0 ) {
- ERROR(i.data.span, E0000, "impl Trait for .. with methods");
+ ERROR(i.span, E0000, "impl Trait for .. with methods");
}
item_context.pop(def.params());
- const_cast< ::AST::Trait*>(def.trait().ent.binding().as_Trait().trait_)->set_is_marker();
+ const_cast< ::AST::Trait*>(def.trait().ent.m_bindings.type.as_Trait().trait_)->set_is_marker();
}
else
{
+ TRACE_FUNCTION_F("impl " << def.trait().ent << " for " << def.type());
item_context.push_self( def.type() );
item_context.push(def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, def.params());
+ item_context.m_ibl_target_generics = &def.params();
Resolve_Absolute_Type(item_context, def.type());
if( def.trait().ent.is_valid() ) {
Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent);
}
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, def.params());
Resolve_Absolute_ImplItems(item_context, e.items());
@@ -2178,15 +2320,18 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(NegImpl,
auto& impl_def = e;
- DEBUG("impl ! " << impl_def.trait().ent << " for " << impl_def.type());
+ TRACE_FUNCTION_F("impl ! " << impl_def.trait().ent << " for " << impl_def.type());
item_context.push_self( impl_def.type() );
item_context.push(impl_def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, impl_def.params());
+ item_context.m_ibl_target_generics = &impl_def.params();
Resolve_Absolute_Type(item_context, impl_def.type());
if( !impl_def.trait().ent.is_valid() )
- BUG(i.data.span, "Encountered negative impl with no trait");
+ BUG(i.span, "Encountered negative impl with no trait");
Resolve_Absolute_Path(item_context, impl_def.trait().sp, Context::LookupMode::Type, impl_def.trait().ent);
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, impl_def.params());
// No items
diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp
index 659bded4..1511583e 100644
--- a/src/resolve/index.cpp
+++ b/src/resolve/index.cpp
@@ -17,7 +17,7 @@ enum class IndexName
Value,
};
-void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub);
+void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub);
::std::ostream& operator<<(::std::ostream& os, const IndexName& loc)
{
@@ -32,7 +32,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
}
throw "";
}
-::std::unordered_map< ::std::string, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) {
+::std::unordered_map< RcString, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) {
switch(location)
{
case IndexName::Namespace:
@@ -57,8 +57,9 @@ namespace {
}
} // namespace
-void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item(const Span& sp, AST::Module& mod, IndexName location, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
+ ASSERT_BUG(sp, ir.m_bindings.has_binding(), "");
auto& list = get_mod_index(mod, location);
bool was_import = (ir != mod.path() + name);
@@ -66,7 +67,7 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std
{
if( error_on_collision )
{
- ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ")");
+ ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ") " << ir << ", and " << list[name].path);
}
else if( list.at(name).path == ir )
{
@@ -89,12 +90,12 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std
assert(rec.second);
}
}
-void _add_item_type(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item_type(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
_add_item(sp, mod, IndexName::Namespace, name, is_pub, ::AST::Path(ir), error_on_collision);
_add_item(sp, mod, IndexName::Type, name, is_pub, mv$(ir), error_on_collision);
}
-void _add_item_value(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item_value(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
_add_item(sp, mod, IndexName::Value, name, is_pub, mv$(ir), error_on_collision);
}
@@ -120,52 +121,57 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod)
(NegImpl,
),
+ (Macro,
+ // TODO: Add to a macro list
+ ),
+
(Use,
// Skip for now
),
// - Types/modules only
(Module,
- p.bind( ::AST::PathBinding::make_Module({&e}) );
- _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Module({&e});
+ _add_item(i.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
),
(Crate,
- ASSERT_BUG(i.data.span, crate.m_extern_crates.count(e.name) > 0, "Referenced crate '" << e.name << "' isn't loaded for `extern crate`");
- p.bind( ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) }) );
- _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
+ ASSERT_BUG(i.span, crate.m_extern_crates.count(e.name) > 0, "Referenced crate '" << e.name << "' isn't loaded for `extern crate`");
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) });
+ _add_item(i.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
),
(Enum,
- p.bind( ::AST::PathBinding::make_Enum({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Union,
- p.bind( ::AST::PathBinding::make_Union({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Union({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Trait,
- p.bind( ::AST::PathBinding::make_Trait({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Type,
- p.bind( ::AST::PathBinding::make_TypeAlias({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
// - Mixed
(Struct,
- p.bind( ::AST::PathBinding::make_Struct({&e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({&e});
// - If the struct is a tuple-like struct (or unit-like), it presents in the value namespace
if( ! e.m_data.is_Struct() ) {
- _add_item_value(i.data.span, mod, i.name, i.is_pub, p);
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, p);
}
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
// - Values only
(Function,
- p.bind( ::AST::PathBinding::make_Function({&e}) );
- _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Function({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Static,
- p.bind( ::AST::PathBinding::make_Static({&e}) );
- _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, mv$(p));
)
)
}
@@ -176,80 +182,79 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod)
{
if( ! i.data.is_Use() )
continue ;
- const auto& i_data = i.data.as_Use();
- if( i.name != "" )
+ for(const auto& i_data : i.data.as_Use().entries)
+ if( i_data.name != "" )
{
// TODO: Ensure that the path is canonical?
const auto& sp = i_data.sp;
- struct H {
- static void handle_pb(const Span& sp, AST::Module& mod, const AST::Named<AST::Item>& i, const AST::PathBinding& pb, bool allow_collide)
- {
- const auto& i_data = i.data.as_Use();
- TU_MATCH(::AST::PathBinding, (pb), (e),
- (Unbound,
- ),
- (Variable,
- BUG(sp, "Import was bound to variable");
- ),
- (TypeParameter,
- BUG(sp, "Import was bound to type parameter");
- ),
- (TraitMethod,
- BUG(sp, "Import was bound to trait method");
- ),
- (StructMethod,
- BUG(sp, "Import was bound to struct method");
- ),
-
- (Crate , _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Module, _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Enum, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Union, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Trait, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (TypeAlias,_add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
-
- (Struct,
- _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- // - If the struct is a tuple-like struct, it presents in the value namespace
- assert(e.struct_ || e.hir);
- if( !(e.struct_ ? e.struct_->m_data.is_Struct() : e.hir->m_data.is_Named()) )
- {
- _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- }
- ),
- (Static , _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Function, _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (EnumVar ,
- bool is_struct = false;
- if( e.enum_ ) {
- ASSERT_BUG(sp, e.idx < e.enum_->variants().size(), "Variant out of range for " << i_data.path);
- is_struct = e.enum_->variants().at(e.idx).m_data.is_Struct();
- }
- else {
- //ASSERT_BUG(sp, e.idx < e.hir->m_variants.size(), "Variant out of range for " << i_data.path);
- is_struct = TU_TEST1(e.hir->m_data, Data, .at(e.idx).is_struct);
- }
- if( is_struct )
- _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- else
- _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- )
- )
+ ASSERT_BUG(sp, i_data.path.m_bindings.has_binding(), "`use " << i_data.path << "` left unbound in module " << mod.path());
+
+ bool allow_collide = false;
+ // - Types
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.type), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a type/module");
}
- };
- if( i_data.path.binding().is_Unbound() ) {
- BUG(sp, "`use " << i_data.path << "` left unbound in module " << mod.path());
- }
- else {
- H::handle_pb(sp, mod, i, i_data.path.binding(), false);
- }
- if( i_data.alt_binding.is_Unbound() ) {
- // Doesn't matter
- }
- else {
- H::handle_pb(sp, mod, i, i_data.alt_binding, true);
- }
+ TU_ARMA(TypeParameter, e)
+ BUG(sp, "Import was bound to type parameter");
+ TU_ARMA(Crate , e)
+ _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Module, e)
+ _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Enum, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Union, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Trait, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(TypeAlias, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Struct, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(EnumVar, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ }}
+ // - Values
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.value), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a value");
+ }
+ TU_ARMA(Variable, e)
+ BUG(sp, "Import was bound to a variable");
+ TU_ARMA(Struct, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(EnumVar, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Static , e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Function, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ }}
+ // - Macros
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.macro), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a macro");
+ }
+ TU_ARMA(MacroRules, e) {
+ ::std::vector<RcString> path;
+ path.push_back( i_data.path.m_class.as_Absolute().crate );
+ for(const auto& node : i_data.path.m_class.as_Absolute().nodes )
+ path.push_back( node.name() );
+ mod.m_macro_imports.push_back({
+ i.is_pub, i_data.name, mv$(path), e.mac
+ });
+ }
+ TU_ARMA(ProcMacro, e) {
+ TODO(sp, "ProcMacro import");
+ }
+ TU_ARMA(ProcMacroAttribute, e) {
+ TODO(sp, "ProcMacroAttribute import");
+ }
+ TU_ARMA(ProcMacroDerive, e) {
+ TODO(sp, "ProcMacroDerive import");
+ }
+ }}
}
else
{
@@ -285,35 +290,59 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
{
for(const auto& it : hmod.m_mod_items) {
const auto& ve = *it.second;
- if( ve.is_public ) {
+ if( ve.publicity.is_global() ) {
+ const auto* vep = &ve.ent;
AST::Path p;
- if( ve.ent.is_Import() ) {
- p = hir_to_ast( ve.ent.as_Import().path );
+ if( vep->is_Import() ) {
+ const auto& spath = vep->as_Import().path;
+ p = hir_to_ast( spath );
+
+ ASSERT_BUG(sp, crate.m_extern_crates.count(spath.m_crate_name) == 1, "Crate " << spath.m_crate_name << " is not loaded");
+ const auto* hmod = &crate.m_extern_crates.at(spath.m_crate_name).m_hir->m_root_module;
+ for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) {
+ const auto& hit = hmod->m_mod_items.at( spath.m_components[i] );
+ // Only support enums on the penultimate component
+ if( i == spath.m_components.size()-2 && hit->ent.is_Enum() ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, 0});
+ _add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false );
+ hmod = nullptr;
+ break ;
+ }
+ ASSERT_BUG(sp, hit->ent.is_Module(), "Path component " << spath.m_components[i] << " of " << spath << " is not a module, instead " << hit->ent.tag_str());
+ hmod = &hit->ent.as_Module();
+ }
+ if( !hmod )
+ continue ;
+ vep = &hmod->m_mod_items.at( spath.m_components.back() )->ent;
}
else {
p = path + it.first;
}
- TU_MATCHA( (ve.ent), (e),
+ TU_MATCHA( (*vep), (e),
(Import,
//throw "";
+ TODO(sp, "Get binding for HIR import? " << e.path);
),
(Module,
- p.bind( ::AST::PathBinding::make_Module({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
),
(Trait,
- p.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(Struct,
- p.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- p.bind( ::AST::PathBinding::make_Union({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
),
(Enum,
- p.bind( ::AST::PathBinding::make_Enum({nullptr}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr});
),
(TypeAlias,
- p.bind( ::AST::PathBinding::make_TypeAlias({nullptr}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
+ ),
+ (ExternType,
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
)
)
_add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false );
@@ -321,7 +350,7 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
}
for(const auto& it : hmod.m_value_items) {
const auto& ve = *it.second;
- if( ve.is_public ) {
+ if( ve.publicity.is_global() ) {
AST::Path p;
const auto* vep = &ve.ent;
if( ve.ent.is_Import() ) {
@@ -333,8 +362,8 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) {
const auto& it = hmod->m_mod_items.at( spath.m_components[i] );
if(it->ent.is_Enum()) {
- ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, "");
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, 0}) );
+ ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, "Found enum not at penultimate component of HIR import path");
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, 0}); // TODO: What's the index?
vep = nullptr;
hmod = nullptr;
break ;
@@ -355,20 +384,20 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
throw "";
),
(Constant,
- p.bind( ::AST::PathBinding::make_Static({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr});
),
(Static,
- p.bind( ::AST::PathBinding::make_Static({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr});
),
// TODO: What if these refer to an enum variant?
(StructConstant,
- p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() });
),
(StructConstructor,
- p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() });
),
(Function,
- p.bind( ::AST::PathBinding::make_Function({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr});
)
)
}
@@ -406,26 +435,36 @@ void Resolve_Index_Module_Wildcard__submod(AST::Crate& crate, AST::Module& dst_m
{
if( ! i.data.is_Use() )
continue ;
- if( i.name != "" )
- continue ;
- Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, i.data.as_Use(), import_as_pub);
+ for(const auto& e : i.data.as_Use().entries)
+ {
+ if( e.name != "" )
+ continue ;
+ Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, e, import_as_pub);
+ }
}
}
stack.erase(&src_mod);
}
-void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub)
+void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub)
{
const auto& sp = i_data.sp;
- const auto& b = i_data.path.binding();
+ const auto& b = i_data.path.m_bindings.type;
- TU_IFLET(::AST::PathBinding, b, Crate, e,
+ TU_IFLET(::AST::PathBinding_Type, b, Crate, e,
DEBUG("Glob crate " << i_data.path);
const auto& hmod = e.crate_->m_hir->m_root_module;
Resolve_Index_Module_Wildcard__glob_in_hir_mod(sp, crate, dst_mod, hmod, i_data.path, is_pub);
+ // TODO: Macros too
+ for(const auto& pm : e.crate_->m_hir->m_proc_macros)
+ {
+ dst_mod.m_macro_imports.push_back({
+ is_pub, pm.name, make_vec2(e.crate_->m_hir->m_crate_name, pm.name), nullptr
+ });
+ }
)
- else TU_IFLET(::AST::PathBinding, b, Module, e,
+ else TU_IFLET(::AST::PathBinding_Type, b, Module, e,
DEBUG("Glob mod " << i_data.path);
if( !e.module_ )
{
@@ -438,7 +477,9 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
Resolve_Index_Module_Wildcard__submod(crate, dst_mod, *e.module_, is_pub);
}
)
- else TU_IFLET(::AST::PathBinding, b, Enum, e,
+ else if( const auto* ep = b.opt_Enum() )
+ {
+ const auto& e = *ep;
ASSERT_BUG(sp, e.enum_ || e.hir, "Glob import but enum pointer not set - " << i_data.path);
if( e.enum_ )
{
@@ -446,11 +487,12 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
unsigned int idx = 0;
for( const auto& ev : e.enum_->variants() ) {
::AST::Path p = i_data.path + ev.m_name;
- p.bind( ::AST::PathBinding::make_EnumVar({e.enum_, idx}) );
if( ev.m_data.is_Struct() ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, idx});
_add_item_type ( sp, dst_mod, ev.m_name, is_pub, mv$(p), false );
}
else {
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, idx});
_add_item_value( sp, dst_mod, ev.m_name, is_pub, mv$(p), false );
}
@@ -467,7 +509,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
for(const auto& ev : de->variants)
{
::AST::Path p = i_data.path + ev.name;
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir});
_add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false );
@@ -480,12 +522,13 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
for(const auto& ev : *de)
{
::AST::Path p = i_data.path + ev.name;
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) );
if( ev.is_struct ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, idx, e.hir});
_add_item_type ( sp, dst_mod, ev.name, is_pub, mv$(p), false );
}
else {
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir});
_add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false );
}
@@ -493,7 +536,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
}
}
}
- )
+ }
else
{
BUG(sp, "Invalid path binding for glob import: " << b.tag_str() << " - "<<i_data.path);
@@ -515,9 +558,12 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod)
{
if( ! i.data.is_Use() )
continue ;
- if( i.name != "" )
- continue ;
- Resolve_Index_Module_Wildcard__use_stmt(crate, mod, i.data.as_Use(), i.is_pub);
+ for(const auto& e : i.data.as_Use().entries )
+ {
+ if( e.name != "" )
+ continue ;
+ Resolve_Index_Module_Wildcard__use_stmt(crate, mod, e, i.is_pub);
+ }
}
// Mark this as having all the items it ever will.
@@ -598,9 +644,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp
{
TU_IFLET( ::HIR::TypeItem, it_m->second->ent, Import, e,
// Replace the path with this path (maintaining binding)
- auto binding = path.binding().clone();
+ auto bindings = path.m_bindings.clone();
path = hir_to_ast(e.path);
- path.bind( mv$(binding) );
+ path.m_bindings = mv$(bindings);
)
return ;
}
@@ -611,9 +657,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp
{
TU_IFLET( ::HIR::ValueItem, it_v->second->ent, Import, e,
// Replace the path with this path (maintaining binding)
- auto binding = path.binding().clone();
+ auto bindings = path.m_bindings.clone();
path = hir_to_ast(e.path);
- path.bind( mv$(binding) );
+ path.m_bindings = mv$(bindings);
)
return ;
}
@@ -648,27 +694,26 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span&
auto new_path = ie.path;
for(unsigned int j = i+1; j < info.nodes.size(); j ++)
new_path.nodes().push_back( mv$(info.nodes[j]) );
- new_path.bind( path.binding().clone() );
+ new_path.m_bindings = path.m_bindings.clone();
path = mv$(new_path);
return Resolve_Index_Module_Normalise_Path(crate, sp, path, loc);
}
else {
- TU_MATCH_DEF(::AST::PathBinding, (ie.path.binding()), (e),
- (
+ TU_MATCH_HDR( (ie.path.m_bindings.type), {)
+ default:
BUG(sp, "Path " << path << " pointed to non-module " << ie.path);
- ),
- (Module,
+ TU_ARM( ie.path.m_bindings.type, Module, e) {
mod = e.module_;
- ),
- (Crate,
+ }
+ TU_ARM( ie.path.m_bindings.type, Crate, e) {
Resolve_Index_Module_Normalise_Path_ext(crate, sp, path, loc, *e.crate_, i+1);
return false;
- ),
- (Enum,
+ }
+ TU_ARM( ie.path.m_bindings.type, Enum, e) {
// NOTE: Just assuming that if an Enum is hit, it's sane
return false;
- )
- )
+ }
+ }
}
}
@@ -716,7 +761,7 @@ void Resolve_Index_Module_Normalise(const ::AST::Crate& crate, const Span& mod_s
for( auto& item : mod.items() )
{
TU_IFLET(AST::Item, item.data, Module, e,
- Resolve_Index_Module_Normalise(crate, item.data.span, e);
+ Resolve_Index_Module_Normalise(crate, item.span, e);
)
}
diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp
index 23f7e70c..8a9a3167 100644
--- a/src/resolve/use.cpp
+++ b/src/resolve/use.cpp
@@ -22,8 +22,8 @@ enum class Lookup
::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path);
void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, ::std::span< const ::AST::Module* > parent_modules={});
-::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow=Lookup::Any);
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow);
+::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules);
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start);
void Resolve_Use(::AST::Crate& crate)
@@ -51,7 +51,7 @@ void Resolve_Use(::AST::Crate& crate)
// How can this happen?
DEBUG("Relative " << path);
// EVIL HACK: If the current module is an anon module, refer to the parent
- if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) {
+ if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) {
AST::Path np("", {});
for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -65,7 +65,7 @@ void Resolve_Use(::AST::Crate& crate)
(Self,
DEBUG("Self " << path);
// EVIL HACK: If the current module is an anon module, refer to the parent
- if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) {
+ if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) {
AST::Path np("", {});
for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -86,7 +86,7 @@ void Resolve_Use(::AST::Crate& crate)
// TODO: Do this in a cleaner manner.
unsigned int n_anon = 0;
// Skip any anon modules in the way (i.e. if the current module is an anon, go to the parent)
- while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name()[0] == '#' )
+ while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name().c_str()[0] == '#' )
n_anon ++;
for( unsigned int i = 0; i < base_path.nodes().size() - e.count - n_anon; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -113,60 +113,42 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
auto& use_stmt_data = use_stmt.data.as_Use();
const Span& span = use_stmt_data.sp;
- use_stmt_data.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_stmt_data.path));
- if( !use_stmt_data.path.m_class.is_Absolute() )
- BUG(span, "Use path is not absolute after absolutisation");
-
- // TODO: Have Resolve_Use_GetBinding return the actual path
- use_stmt_data.path.bind( Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules) );
- DEBUG("'" << use_stmt.name << "' = " << use_stmt_data.path);
-
- // - If doing a glob, ensure the item type is valid
- if( use_stmt.name == "" )
+ for(auto& use_ent : use_stmt_data.entries)
{
- TU_MATCH_DEF(::AST::PathBinding, (use_stmt_data.path.binding()), (e),
- (
- ERROR(span, E0000, "Wildcard import of invalid item type - " << use_stmt_data.path);
- ),
- (Enum,
- ),
- (Crate,
- ),
- (Module,
+ use_ent.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_ent.path));
+ if( !use_ent.path.m_class.is_Absolute() )
+ BUG(span, "Use path is not absolute after absolutisation");
+
+ // NOTE: Use statements can refer to _three_ different items
+ // - types/modules ("type namespace")
+ // - values ("value namespace")
+ // - macros ("macro namespace")
+ // TODO: Have Resolve_Use_GetBinding return the actual path
+ use_ent.path.m_bindings = Resolve_Use_GetBinding(span, crate, path, use_ent.path, parent_modules);
+ if( !use_ent.path.m_bindings.has_binding() )
+ {
+ ERROR(span, E0000, "Unable to resolve `use` target " << use_ent.path);
+ }
+ DEBUG("'" << use_ent.name << "' = " << use_ent.path);
+
+ // - If doing a glob, ensure the item type is valid
+ if( use_ent.name == "" )
+ {
+ TU_MATCH_DEF(::AST::PathBinding_Type, (use_ent.path.m_bindings.type), (e),
+ (
+ ERROR(span, E0000, "Wildcard import of invalid item type - " << use_ent.path);
+ ),
+ (Enum,
+ ),
+ (Crate,
+ ),
+ (Module,
+ )
)
- )
- }
- else
- {
- // TODO: Handle case where a use can resolve to two different items (one value, one type/namespace)
- // - Easiest way is with an extra binding slot
- Lookup allow = Lookup::Any;
- switch( use_stmt_data.path.binding().tag() )
+ }
+ else
{
- case ::AST::PathBinding::TAG_Crate:
- case ::AST::PathBinding::TAG_Module:
- case ::AST::PathBinding::TAG_Trait:
- case ::AST::PathBinding::TAG_TypeAlias:
- case ::AST::PathBinding::TAG_Enum:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_Struct:
- case ::AST::PathBinding::TAG_Union:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_EnumVar:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_Static:
- case ::AST::PathBinding::TAG_Function:
- allow = Lookup::Type;
- break;
- // DEAD, Unbound, ...
- default: break;
- }
- ASSERT_BUG(span, allow != Lookup::Any, "Invalid path binding type in use statement - " << use_stmt_data.path);
- use_stmt_data.alt_binding = Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules, allow);
- DEBUG("- Alt Binding: " << use_stmt_data.alt_binding);
+ }
}
}
@@ -235,6 +217,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
(None,
// Deleted, ignore
),
+ (MacroInv,
+ // TODO: Should this already be deleted?
+ ),
(Type,
),
(Function,
@@ -264,25 +249,24 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
}
}
-::AST::PathBinding Resolve_Use_GetBinding_Mod(
+::AST::Path::Bindings Resolve_Use_GetBinding_Mod(
const Span& span,
- const ::AST::Crate& crate, const ::AST::Module& mod,
- const ::std::string& des_item_name,
- ::std::span< const ::AST::Module* > parent_modules,
- Lookup allow
+ const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Module& mod,
+ const RcString& des_item_name,
+ ::std::span< const ::AST::Module* > parent_modules
)
{
+ ::AST::Path::Bindings rv;
// If the desired item is an anon module (starts with #) then parse and index
- if( des_item_name.size() > 0 && des_item_name[0] == '#' ) {
+ if( des_item_name.size() > 0 && des_item_name.c_str()[0] == '#' ) {
unsigned int idx = 0;
if( ::std::sscanf(des_item_name.c_str(), "#%u", &idx) != 1 ) {
BUG(span, "Invalid anon path segment '" << des_item_name << "'");
}
- if( idx >= mod.anon_mods().size() ) {
- BUG(span, "Invalid anon path segment '" << des_item_name << "'");
- }
+ ASSERT_BUG(span, idx < mod.anon_mods().size(), "Invalid anon path segment '" << des_item_name << "'");
assert( mod.anon_mods()[idx] );
- return ::AST::PathBinding::make_Module({&*mod.anon_mods()[idx], nullptr});
+ rv.type = ::AST::PathBinding_Type::make_Module({&*mod.anon_mods()[idx], nullptr});
+ return rv;
}
// Seach for the name defined in the module.
@@ -292,8 +276,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
continue ;
if( item.name == des_item_name ) {
- //if( allow != Lookup::Any )
- // DEBUG(mod.path() << " " << des_item_name << " " << item.data.tag_str());
TU_MATCH(::AST::Item, (item.data), (e),
(None,
// IMPOSSIBLE - Handled above
@@ -301,6 +283,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
(MacroInv,
BUG(span, "Hit MacroInv in use resolution");
),
+ (Macro,
+ //rv.macro = ::AST::PathBinding_Macro::make_MacroRules({nullptr, e.get()});
+ ),
(Use,
continue; // Skip for now
),
@@ -314,48 +299,48 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
BUG(span, "Hit Extern in use resolution");
),
(Crate,
- if( allow != Lookup::Value )
- ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded");
- return ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) });
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded");
+ rv.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) });
),
(Type,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_TypeAlias({&e});
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({&e});
),
(Trait,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Trait({&e});
+ rv.type = ::AST::PathBinding_Type::make_Trait({&e});
),
(Function,
- if( allow != Lookup::Type )
- return ::AST::PathBinding::make_Function({&e});
+ rv.value = ::AST::PathBinding_Value::make_Function({&e});
),
(Static,
- if( allow != Lookup::Type )
- return ::AST::PathBinding::make_Static({&e});
+ rv.value = ::AST::PathBinding_Value::make_Static({&e});
),
(Struct,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Struct({&e});
- if( e.m_data.is_Tuple() && allow != Lookup::Type )
- return ::AST::PathBinding::make_Struct({&e});
+ // TODO: What happens with name collisions?
+ if( !e.m_data.is_Struct() )
+ rv.value = ::AST::PathBinding_Value::make_Struct({&e});
+ rv.type = ::AST::PathBinding_Type::make_Struct({&e});
),
(Enum,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Enum({&e});
+ rv.type = ::AST::PathBinding_Type::make_Enum({&e});
),
(Union,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Union({&e});
+ rv.type = ::AST::PathBinding_Type::make_Union({&e});
),
(Module,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Module({&e});
+ rv.type = ::AST::PathBinding_Type::make_Module({&e});
)
)
}
}
+ // TODO: macros
+ for(const auto& mac : mod.macros())
+ {
+ if( mac.name == des_item_name ) {
+ rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ nullptr, &*mac.data });
+ break;
+ }
+ }
// Imports
for( const auto& imp : mod.items() )
@@ -363,127 +348,153 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
if( ! imp.data.is_Use() )
continue ;
const auto& imp_data = imp.data.as_Use();
- const Span& sp2 = imp_data.sp;
- if( imp.name == des_item_name ) {
- DEBUG("- Named import " << imp.name << " = " << imp_data);
- if( imp_data.path.binding().is_Unbound() ) {
- DEBUG(" > Needs resolve");
- // TODO: Handle possibility of recursion
- //out_path = imp_data.path;
- return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules, allow);
- }
- else {
- if( allow != Lookup::Any && allow != Lookup::AnyOpt )
+ for( const auto& imp_e : imp_data.entries )
+ {
+ const Span& sp2 = imp_e.sp;
+ if( imp_e.name == des_item_name ) {
+ DEBUG("- Named import " << imp_e.name << " = " << imp_e.path);
+ if( !imp_e.path.m_bindings.has_binding() )
{
- switch( imp_data.path.binding().tag() )
+ DEBUG(" > Needs resolve p=" << &imp_e.path);
+ static ::std::vector<const ::AST::Path*> s_mods;
+ if( ::std::find(s_mods.begin(), s_mods.end(), &imp_e.path) == s_mods.end() )
{
- case ::AST::PathBinding::TAG_Crate:
- case ::AST::PathBinding::TAG_Module:
- case ::AST::PathBinding::TAG_Trait:
- case ::AST::PathBinding::TAG_TypeAlias:
- case ::AST::PathBinding::TAG_Enum:
- if( allow != Lookup::Type )
- continue;
- break;
- case ::AST::PathBinding::TAG_Struct:
- break;
- case ::AST::PathBinding::TAG_EnumVar:
- break;
- case ::AST::PathBinding::TAG_Static:
- case ::AST::PathBinding::TAG_Function:
- if( allow != Lookup::Value )
- continue;
- break;
- default:
- break;
+ s_mods.push_back(&imp_e.path);
+ rv.merge_from( Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) );
+ s_mods.pop_back();
+ }
+ else
+ {
+ DEBUG("Recursion on path " << &imp_e.path << " " << imp_e.path);
}
- }
- //out_path = imp_data.path;
- return imp_data.path.binding().clone();
- }
- }
- if( imp.is_pub && imp.name == "" ) {
- DEBUG("- Search glob of " << imp_data.path);
- // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here)
- ::AST::PathBinding binding_;
- const auto* binding = &imp_data.path.binding();
- if( binding->is_Unbound() ) {
- DEBUG("Temp resolving wildcard " << imp_data);
- // Handle possibility of recursion
- static ::std::vector<const ::AST::UseStmt*> resolve_stack_ptrs;
- if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() )
- {
- resolve_stack_ptrs.push_back( &imp_data );
- binding_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules);
- // *waves hand* I'm not evil.
- const_cast< ::AST::PathBinding&>( imp_data.path.binding() ) = binding_.clone();
- binding = &binding_;
- resolve_stack_ptrs.pop_back();
}
else {
- continue ;
+ //out_path = imp_e.path;
+ rv.merge_from( imp_e.path.m_bindings.clone() );
}
- }
- else {
- //out_path = imp_data.path;
+ continue ;
}
- TU_MATCH_DEF(::AST::PathBinding, (*binding), (e),
- (
- BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str());
- ),
- (Crate,
- assert(e.crate_);
- const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module;
- auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow);
- if( ! rv.is_Unbound() ) {
- return mv$(rv);
- }
- ),
- (Module,
- auto allow_inner = (allow == Lookup::Any ? Lookup::AnyOpt : allow);
- assert(e.module_);
- // TODO: Prevent infinite recursion?
- auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner);
- if( ! rv.is_Unbound() ) {
- return mv$(rv);
- }
- ),
- (Enum,
- assert(e.enum_ || e.hir);
- if( e.enum_ ) {
- const auto& enm = *e.enum_;
- unsigned int i = 0;
- for(const auto& var : enm.variants())
+ // TODO: Correct privacy rules (if the origin of this lookup can see this item)
+ if( (imp.is_pub || mod.path().is_parent_of(source_mod_path)) && imp_e.name == "" )
+ {
+ DEBUG("- Search glob of " << imp_e.path << " in " << mod.path());
+ // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here)
+ ::AST::Path::Bindings bindings_;
+ const auto* bindings = &imp_e.path.m_bindings;
+ if( bindings->type.is_Unbound() ) {
+ DEBUG("Temp resolving wildcard " << imp_e.path);
+ // Handle possibility of recursion
+ static ::std::vector<const ::AST::UseItem*> resolve_stack_ptrs;
+ if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() )
{
- if( var.m_name == des_item_name ) {
- return ::AST::PathBinding::make_EnumVar({ &enm, i });
+ resolve_stack_ptrs.push_back( &imp_data );
+ bindings_ = Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules);
+ if( bindings_.type.is_Unbound() ) {
+ DEBUG("Recursion detected, skipping " << imp_e.path);
+ continue ;
}
- i ++;
+ // *waves hand* I'm not evil.
+ const_cast< ::AST::Path::Bindings&>( imp_e.path.m_bindings ) = bindings_.clone();
+ bindings = &bindings_;
+ resolve_stack_ptrs.pop_back();
+ }
+ else {
+ continue ;
}
}
else {
- const auto& enm = *e.hir;
- auto idx = enm.find_variant(des_item_name);
- if( idx != SIZE_MAX )
- {
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ //out_path = imp_e.path;
+ }
+
+ TU_MATCH_HDRA( (bindings->type), {)
+ TU_ARMA(Crate, e) {
+ assert(e.crate_);
+ const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module;
+ auto imp_rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0);
+ if( imp_rv.has_binding() ) {
+ rv.merge_from( imp_rv );
+ }
}
+ TU_ARMA(Module, e) {
+ if( e.module_ ) {
+ // TODO: Prevent infinite recursion?
+ static ::std::vector<const AST::Module*> s_use_glob_mod_stack;
+ if( ::std::find(s_use_glob_mod_stack.begin(), s_use_glob_mod_stack.end(), &*e.module_) == s_use_glob_mod_stack.end() )
+ {
+ s_use_glob_mod_stack.push_back( &*e.module_ );
+ rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, mod.path(), *e.module_, des_item_name, {}) );
+ s_use_glob_mod_stack.pop_back();
+ }
+ else
+ {
+ DEBUG("Recursion prevented of " << e.module_->path());
+ }
+ }
+ else if( e.hir ) {
+ const ::HIR::Module& hmod = *e.hir;
+ rv.merge_from( Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0) );
+ }
+ else {
+ BUG(span, "NULL module for binding on glob of " << imp_e.path);
+ }
+ }
+ TU_ARMA(Enum, e) {
+ assert(e.enum_ || e.hir);
+ if( e.enum_ ) {
+ const auto& enm = *e.enum_;
+ unsigned int i = 0;
+ for(const auto& var : enm.variants())
+ {
+ if( var.m_name == des_item_name ) {
+ ::AST::Path::Bindings tmp_rv;
+ if( var.m_data.is_Struct() )
+ tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i });
+ else
+ tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i });
+ rv.merge_from(tmp_rv);
+ break;
+ }
+ i ++;
+ }
+ }
+ else {
+ const auto& enm = *e.hir;
+ auto idx = enm.find_variant(des_item_name);
+ if( idx != SIZE_MAX )
+ {
+ ::AST::Path::Bindings tmp_rv;
+ if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) {
+ tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ }
+ else {
+ tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ }
+ rv.merge_from(tmp_rv);
+ break;
+ }
+ }
+ } break;
+ default:
+ BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str());
+ break;
}
- )
- )
+ }
}
}
+ if( rv.has_binding() )
+ {
+ return rv;
+ }
- if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) {
+ if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name().c_str()[0] == '#' ) {
assert( parent_modules.size() > 0 );
- return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1), allow);
+ return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1));
}
else {
- if( allow == Lookup::Any )
- ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path());
- else
- return ::AST::PathBinding::make_Unbound({});
+ //if( allow == Lookup::Any )
+ // ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path());
+ return ::AST::Path::Bindings();
}
}
@@ -532,13 +543,15 @@ namespace {
}
}
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start)
{
- TRACE_FUNCTION_F(path);
+ ::AST::Path::Bindings rv;
+ TRACE_FUNCTION_F(path << " offset " << start);
const auto& nodes = path.nodes();
const ::HIR::Module* hmod = &hmodr;
for(unsigned int i = start; i < nodes.size() - 1; i ++)
{
+ DEBUG("m_mod_items = {" << FMT_CB(ss, for(const auto& e : hmod->m_mod_items) ss << e.first << ", ";) << "}");
auto it = hmod->m_mod_items.find(nodes[i].name());
if( it == hmod->m_mod_items.end() ) {
// BZZT!
@@ -566,7 +579,13 @@ namespace {
if( idx == SIZE_MAX ) {
ERROR(span, E0000, "Unable to find variant " << path);
}
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ }
+ else {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ }
+ return rv;
}
else {
hmod = reinterpret_cast<const ::HIR::Module*>(ptr);
@@ -586,16 +605,23 @@ namespace {
if(idx == SIZE_MAX) {
ERROR(span, E0000, "Unable to find variant " << path);
}
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ }
+ else {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ }
+ return rv;
)
)
}
- if( allow != Lookup::Value )
+ // - namespace/type items
{
auto it = hmod->m_mod_items.find(nodes.back().name());
- if( it != hmod->m_mod_items.end() ) {
+ if( it != hmod->m_mod_items.end() )
+ {
const auto* item_ptr = &it->second->ent;
- DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str());
+ DEBUG("E : Mod " << nodes.back().name() << " = " << item_ptr->tag_str());
if( item_ptr->is_Import() ) {
const auto& e = item_ptr->as_Import();
const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name );
@@ -605,94 +631,139 @@ namespace {
p.m_components.pop_back();
const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum();
assert(e.idx < enm.num_variants());
- return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm });
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, e.idx, &enm });
+ }
+ else if( e.path.m_components.empty() )
+ {
+ rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &ec.m_hir->m_root_module});
+ }
+ else
+ {
+ item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- if( e.path.m_components.empty() )
- return ::AST::PathBinding::make_Module({nullptr, &ec.m_hir->m_root_module});
- item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- TU_MATCHA( (*item_ptr), (e),
- (Import,
- BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path);
- ),
- (Module,
- return ::AST::PathBinding::make_Module({nullptr, &e});
- ),
- (TypeAlias,
- return ::AST::PathBinding::make_TypeAlias({nullptr});
- ),
- (Enum,
- return ::AST::PathBinding::make_Enum({nullptr, &e});
- ),
- (Struct,
- return ::AST::PathBinding::make_Struct({nullptr, &e});
- ),
- (Union,
- return ::AST::PathBinding::make_Union({nullptr, &e});
- ),
- (Trait,
- return ::AST::PathBinding::make_Trait({nullptr, &e});
+ if( rv.type.is_Unbound() )
+ {
+ TU_MATCHA( (*item_ptr), (e),
+ (Import,
+ BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path);
+ ),
+ (Module,
+ rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
+ ),
+ (TypeAlias,
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
+ ),
+ (ExternType,
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); // Lazy.
+ ),
+ (Enum,
+ rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
+ ),
+ (Struct,
+ rv.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
+ ),
+ (Union,
+ rv.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
+ ),
+ (Trait,
+ rv.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
+ )
)
- )
+ }
+ }
+ else
+ {
+ DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- if( allow != Lookup::Type )
+ // - Values
{
auto it2 = hmod->m_value_items.find(nodes.back().name());
if( it2 != hmod->m_value_items.end() ) {
const auto* item_ptr = &it2->second->ent;
- DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str());
+ DEBUG("E : Value " << nodes.back().name() << " = " << item_ptr->tag_str());
if( item_ptr->is_Import() ) {
const auto& e = item_ptr->as_Import();
// This doesn't need to recurse - it can just do a single layer (as no Import should refer to another)
const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name );
- if( e.is_variant ) {
+ if( e.is_variant )
+ {
auto p = e.path;
p.m_components.pop_back();
const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum();
assert(e.idx < enm.num_variants());
- return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm });
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, e.idx, &enm });
+ }
+ else
+ {
+ item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- TU_MATCHA( (*item_ptr), (e),
- (Import,
- BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path);
- ),
- (Constant,
- return ::AST::PathBinding::make_Static({ nullptr });
- ),
- (Static,
- return ::AST::PathBinding::make_Static({ nullptr });
- ),
- // TODO: What happens if these two refer to an enum constructor?
- (StructConstant,
- ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
- return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
- ),
- (StructConstructor,
- ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
- return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
- ),
- (Function,
- return ::AST::PathBinding::make_Function({ nullptr });
+ if( rv.value.is_Unbound() )
+ {
+ TU_MATCHA( (*item_ptr), (e),
+ (Import,
+ BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path);
+ ),
+ (Constant,
+ rv.value = ::AST::PathBinding_Value::make_Static({ nullptr });
+ ),
+ (Static,
+ rv.value = ::AST::PathBinding_Value::make_Static({ nullptr });
+ ),
+ // TODO: What happens if these two refer to an enum constructor?
+ (StructConstant,
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
+ rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
+ ),
+ (StructConstructor,
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
+ rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
+ ),
+ (Function,
+ rv.value = ::AST::PathBinding_Value::make_Function({ nullptr });
+ )
)
- )
+ }
+ }
+ else
+ {
+ DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
-
- DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- DEBUG("E : None");
- return ::AST::PathBinding::make_Unbound({});
+ if( rv.type.is_Unbound() && rv.value.is_Unbound() )
+ {
+ DEBUG("E : None");
+ }
+ return rv;
}
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start)
{
- return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start, allow);
+ DEBUG("Crate " << ec.m_name);
+ auto rv = Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start);
+ if( start + 1 == path.nodes().size() )
+ {
+ const auto& name = path.nodes().back().name();
+ auto it = ec.m_hir->m_exported_macros.find( name );
+ if( it != ec.m_hir->m_exported_macros.end() )
+ {
+ rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ &ec, &*it->second });
+ }
+
+ {
+ auto it = ::std::find_if( ec.m_hir->m_proc_macros.begin(), ec.m_hir->m_proc_macros.end(), [&](const auto& pm){ return pm.name == name;} );
+ if( it != ec.m_hir->m_proc_macros.end() )
+ {
+ rv.macro = ::AST::PathBinding_Macro::make_ProcMacro({ &ec, name });
+ }
+ }
+ }
+ return rv;
}
-::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules)
{
TRACE_FUNCTION_F(path);
//::AST::Path rv;
@@ -701,15 +772,18 @@ namespace {
if( path.m_class.is_Absolute() && path.m_class.as_Absolute().crate != "" ) {
const auto& path_abs = path.m_class.as_Absolute();
- ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate), "Crate '" << path_abs.crate << "' not loaded");
- return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0, allow);
+ ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate.c_str()), "Crate '" << path_abs.crate << "' not loaded");
+ return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate.c_str() ), 0);
}
+ ::AST::Path::Bindings rv;
+
const AST::Module* mod = &crate.m_root_module;
const auto& nodes = path.nodes();
if( nodes.size() == 0 ) {
// An import of the root.
- return ::AST::PathBinding::make_Module({ mod, nullptr });
+ rv.type = ::AST::PathBinding_Type::make_Module({ mod, nullptr });
+ return rv;
}
for( unsigned int i = 0; i < nodes.size()-1; i ++ )
{
@@ -718,54 +792,90 @@ namespace {
//rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type);
//const auto& b = rv.binding();
assert(mod);
- auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules, Lookup::Type);
- TU_MATCH_DEF(::AST::PathBinding, (b), (e),
- (
- ERROR(span, E0000, "Unexpected item type " << b.tag_str() << " in import of " << path);
- ),
- (Unbound,
- ERROR(span, E0000, "Cannot find component " << i << " of " << path);
- ),
- (Crate,
+ auto b = Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.at(i).name(), parent_modules);
+ TU_MATCH_HDRA( (b.type), {)
+ default:
+ ERROR(span, E0000, "Unexpected item type " << b.type.tag_str() << " in import of " << path);
+ TU_ARMA(Unbound, e) {
+ ERROR(span, E0000, "Cannot find component " << i << " of " << path << " (" << b.type << ")");
+ }
+ TU_ARMA(Crate, e) {
// TODO: Mangle the original path (or return a new path somehow)
- return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1, allow);
- ),
- (Enum,
- const auto& enum_ = *e.enum_;
+ return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1);
+ }
+ TU_ARMA(Enum, e) {
+ ASSERT_BUG(span, e.enum_ || e.hir, "nullptr enum pointer in node " << i << " of " << path);
+ ASSERT_BUG(span, e.enum_ == nullptr || e.hir == nullptr, "both AST and HIR pointers set in node " << i << " of " << path);
i += 1;
if( i != nodes.size() - 1 ) {
ERROR(span, E0000, "Encountered enum at unexpected location in import");
}
+ ASSERT_BUG(span, i < nodes.size(), "Enum import position error, " << i << " >= " << nodes.size() << " - " << path);
const auto& node2 = nodes[i];
- int variant_index = -1;
- for( unsigned int j = 0; j < enum_.variants().size(); j ++ )
+
+ unsigned variant_index = 0;
+ bool is_value = false;
+ if(e.hir)
{
- if( enum_.variants()[j].m_name == node2.name() ) {
- variant_index = j;
- break ;
+ const auto& enum_ = *e.hir;
+ size_t idx = enum_.find_variant(node2.name());
+ if( idx == ~0u ) {
+ ERROR(span, E0000, "Unknown enum variant " << path);
}
+ TU_MATCH_HDRA( (enum_.m_data), {)
+ TU_ARMA(Value, ve) {
+ is_value = true;
+ }
+ TU_ARMA(Data, ve) {
+ is_value = !ve[idx].is_struct;
+ }
+ }
+ DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value);
}
- if( variant_index < 0 ) {
- ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'");
- }
+ else
+ {
+ const auto& enum_ = *e.enum_;
+ for( const auto& var : enum_.variants() )
+ {
+ if( var.m_name == node2.name() ) {
+ is_value = !var.m_data.is_Struct();
+ break ;
+ }
+ variant_index ++;
+ }
+ if( variant_index == enum_.variants().size() ) {
+ ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'");
+ }
- return ::AST::PathBinding::make_EnumVar({&enum_, static_cast<unsigned int>(variant_index)});
- ),
- (Module,
+ DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str());
+ }
+ if( is_value ) {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, variant_index, e.hir});
+ }
+ else {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, variant_index, e.hir});
+ }
+ return rv;
+ }
+ TU_ARMA(Module, e) {
ASSERT_BUG(span, e.module_ || e.hir, "nullptr module pointer in node " << i << " of " << path);
if( !e.module_ )
{
assert(e.hir);
// TODO: Mangle the original path (or return a new path somehow)
- return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1, allow);
+ return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1);
}
mod = e.module_;
- )
- )
+ }
+ }
}
assert(mod);
- return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules, allow);
+ return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.back().name(), parent_modules);
}
+//::AST::PathBinding_Macro Resolve_Use_GetBinding_Macro(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules)
+//{
+// throw "";
+//}
diff --git a/src/slice.hpp b/src/slice.hpp
new file mode 100644
index 00000000..2011e8c2
--- /dev/null
+++ b/src/slice.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <stddef.h>
+
+template<typename T>
+class slice
+{
+ T* ptr;
+ size_t len;
+public:
+ slice(T* ptr, size_t len): ptr(ptr), len(len) {}
+
+ T* begin() { return ptr; }
+ T* end() { return ptr + len; }
+ const T* begin() const { return ptr; }
+ const T* end() const { return ptr + len; }
+};
+
+namespace std {
+ template<typename T>
+ ostream& operator<<(ostream& os, const slice<T>& x) {
+ os << "[";
+ bool first = true;
+ for(const auto& e : x)
+ {
+ if(!first)
+ os << ",";
+ first = false;
+ os << e;
+ }
+ os << "]";
+ return os;
+ }
+}
+
diff --git a/src/span.cpp b/src/span.cpp
index 34f2637e..7e3968d1 100644
--- a/src/span.cpp
+++ b/src/span.cpp
@@ -22,7 +22,7 @@ Span::Span(const Position& pos):
}
Span::Span():
outer_span(),
- filename("")/*,
+ filename(""),
start_line(0), start_ofs(0),
end_line(0), end_ofs(0) // */
{
@@ -66,10 +66,10 @@ void Span::error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) cons
#endif
}
void Span::warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const {
- print_span_message(*this, [&](auto& os){os << "warning" << tag;}, msg);
+ print_span_message(*this, [&](auto& os){os << "warn:" << tag;}, msg);
}
void Span::note(::std::function<void(::std::ostream&)> msg) const {
- print_span_message(*this, [](auto& os){os << "note";}, msg);
+ print_span_message(*this, [](auto& os){os << "note:";}, msg);
}
::std::ostream& operator<<(::std::ostream& os, const Span& sp)
diff --git a/src/trans/allocator.cpp b/src/trans/allocator.cpp
index 5f61093d..9f5559ae 100644
--- a/src/trans/allocator.cpp
+++ b/src/trans/allocator.cpp
@@ -12,25 +12,14 @@
#define DEF_METHOD(name, ret) { #name, AllocatorDataTy::ret, sizeof(ALLOCATOR_METHODS_ARGS_##name)/sizeof(AllocatorDataTy), ALLOCATOR_METHODS_ARGS_##name }
DEF_METHOD_ARGS(alloc, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(oom, AllocatorDataTy::AllocError)
DEF_METHOD_ARGS(dealloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(usable_size, AllocatorDataTy::LayoutRef)
-DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
+DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Usize)
DEF_METHOD_ARGS(alloc_zeroed, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(alloc_excess, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(realloc_excess, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(grow_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(shrink_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-const AllocatorMethod ALLOCATOR_METHODS[10] = {
+const AllocatorMethod ALLOCATOR_METHODS[4] = {
DEF_METHOD(alloc, ResultPtr),
- DEF_METHOD(oom, Never),
DEF_METHOD(dealloc, Unit),
- DEF_METHOD(usable_size, UsizePair),
DEF_METHOD(realloc, ResultPtr),
- DEF_METHOD(alloc_zeroed, ResultPtr),
- DEF_METHOD(alloc_excess, ResultExcess),
- DEF_METHOD(realloc_excess, ResultExcess),
- DEF_METHOD(grow_in_place, ResultUnit),
- DEF_METHOD(shrink_in_place, ResultUnit)
+ DEF_METHOD(alloc_zeroed, ResultPtr)
};
+const size_t NUM_ALLOCATOR_METHODS = sizeof(ALLOCATOR_METHODS)/sizeof(ALLOCATOR_METHODS[0]);
diff --git a/src/trans/allocator.hpp b/src/trans/allocator.hpp
index 8a4e5186..c124ef57 100644
--- a/src/trans/allocator.hpp
+++ b/src/trans/allocator.hpp
@@ -9,17 +9,12 @@
enum class AllocatorDataTy {
// - Return
- Never, // !
Unit, // ()
ResultPtr, // (..., *mut i8) + *mut u8
- ResultExcess, // (..., *mut i8, *mut i8) + *mut u8
- UsizePair, // (..., *mut usize, *mut usize) + ()
- ResultUnit, // i8
// - Args
Layout, // usize, usize
- LayoutRef, // *const Layout [actually *const i8]
- AllocError, // *const i8
Ptr, // *mut u8
+ Usize, // usize
};
struct AllocatorMethod {
const char* name;
@@ -33,5 +28,6 @@ enum class AllocatorKind {
DefaultExe,
};
-extern const AllocatorMethod ALLOCATOR_METHODS[10];
+extern const AllocatorMethod ALLOCATOR_METHODS[];
+extern const size_t NUM_ALLOCATOR_METHODS;
diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp
new file mode 100644
index 00000000..71f95a26
--- /dev/null
+++ b/src/trans/auto_impls.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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() );
+ }
+ }
+ };
+}
+
+namespace {
+ ::MIR::Param clone_field(const State& state, const Span& sp, ::MIR::Function& mir_fcn, const ::HIR::TypeRef& subty, ::MIR::LValue fld_lvalue)
+ {
+ if( state.resolve.type_is_copy(sp, subty) )
+ {
+ return ::std::move(fld_lvalue);
+ }
+ else
+ {
+ const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
+ // Allocate to locals (one for the `&T`, the other for the cloned `T`)
+ auto borrow_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
+ auto res_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(subty.clone());
+
+ // Call `<T as Clone>::clone`, passing a borrow of the field
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ borrow_lv.clone(),
+ ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Call({
+ static_cast<unsigned>(mir_fcn.blocks.size() + 2), // return block (after the panic block below)
+ static_cast<unsigned>(mir_fcn.blocks.size() + 1), // panic block (next block)
+ res_lv.clone(),
+ ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ),
+ ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) )
+ });
+ mir_fcn.blocks.push_back(::std::move( bb ));
+
+ // Stub panic handling (TODO: Make this iterate `values` and drop all of them)
+ ::MIR::BasicBlock panic_bb;
+ panic_bb.terminator = ::MIR::Terminator::make_Diverge({});
+ mir_fcn.blocks.push_back(::std::move( panic_bb ));
+
+ // Save the output of the `clone` call
+ return ::std::move(res_lv);
+ }
+ }
+}
+
+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::new_Return(),
+ ::MIR::RValue::make_Use( ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) ) )
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else
+ {
+ TU_MATCH_HDRA( (ty.m_data), {)
+ default:
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ TU_ARMA(Path, te) {
+ // closures are identified by the name starting with 'closure#'
+ if( TU_TEST1(te.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
+ const auto& gp = te.path.m_data.as_Generic();
+ const auto& str = state.resolve.m_crate.get_struct_by_path(sp, gp.m_path);
+ Trans_Params p;
+ p.sp = sp;
+ p.pp_impl = gp.m_params.clone();
+ ::std::vector< ::MIR::Param> values; values.reserve( str.m_data.as_Tuple().size() );
+ for(const auto& fld : str.m_data.as_Tuple())
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent;
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) );
+ }
+ // Construct the result value
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Struct({ gp.clone(), mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else {
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ }
+ }
+ TU_ARMA(Array, te) {
+ ASSERT_BUG(sp, te.size_val < 256, "TODO: Is more than 256 elements sane for auto-generated non-Copy Clone impl? " << ty);
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size_val);
+ for(size_t i = 0; i < te.size_val; i ++)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) );
+ }
+ // Construct the result
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Array({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ TU_ARMA(Tuple, te) {
+ assert(te.size() > 0);
+
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size());
+ // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
+ for(const auto& subty : te)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) );
+ }
+
+ // Construct the result tuple
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Tuple({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ }
+ }
+
+ // 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( RcString::new_interned("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } ));
+
+ // Add impl to the crate
+ auto& list = state.crate.m_trait_impls[state.lang_Clone].get_list_for_type_mut(impl.m_type);
+ list.push_back( box$(impl) );
+}
+
+void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list)
+{
+ if( TARGETVER_1_19 )
+ return ;
+
+ 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));
+ }
+
+ auto impl_list_it = crate.m_trait_impls.find(state.lang_Clone);
+ for(const auto& ty : state.done_list)
+ {
+ assert(impl_list_it != crate.m_trait_impls.end());
+ // 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));
+
+ const auto* impl_list = impl_list_it->second.get_list_for_type(ty);
+ ASSERT_BUG(Span(), impl_list, "No impl list of Clone for " << ty);
+ auto& impl = **::std::find_if( impl_list->begin(), impl_list->end(), [&](const auto& i){ return i->m_type == ty; });
+ assert( impl.m_methods.size() == 1 );
+ e->ptr = &impl.m_methods.begin()->second.data;
+ }
+}
+
diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp
index 9e93caba..3a75e623 100644
--- a/src/trans/codegen.cpp
+++ b/src/trans/codegen.cpp
@@ -15,19 +15,23 @@
#include "codegen.hpp"
#include "monomorphise.hpp"
-void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable)
+void Trans_Codegen(const ::std::string& outfile, CodegenOutput out_ty, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, const ::std::string& hir_file)
{
static Span sp;
- ::std::unique_ptr<CodeGenerator> codegen;
+ ::std::unique_ptr<CodeGenerator> codegen;
if( opt.mode == "monomir" )
{
codegen = Trans_Codegen_GetGenerator_MonoMir(crate, outfile);
}
- else
+ else if( opt.mode == "c" )
{
codegen = Trans_Codegen_GetGeneratorC(crate, outfile);
}
+ else
+ {
+ BUG(sp, "Unknown codegen mode '" << opt.mode << "'");
+ }
// 1. Emit structure/type definitions.
// - Emit in the order they're needed.
@@ -43,6 +47,9 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const
TU_MATCHA( (te.binding), (tpb),
(Unbound, throw ""; ),
(Opaque, throw ""; ),
+ (ExternType,
+ //codegen->emit_extern_type(sp, te.path.m_data.as_Generic(), *tpb);
+ ),
(Struct,
codegen->emit_struct(sp, te.path.m_data.as_Generic(), *tpb);
),
@@ -186,6 +193,6 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const
}
}
- codegen->finalise(is_executable, opt);
+ codegen->finalise(opt, out_ty, hir_file);
}
diff --git a/src/trans/codegen.hpp b/src/trans/codegen.hpp
index b769e350..070e0232 100644
--- a/src/trans/codegen.hpp
+++ b/src/trans/codegen.hpp
@@ -27,7 +27,7 @@ class CodeGenerator
{
public:
virtual ~CodeGenerator() {}
- virtual void finalise(bool is_executable, const TransOptions& opt) {}
+ virtual void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) {}
// Called on all types directly mentioned (e.g. variables, arguments, and fields)
// - Inner-most types are visited first.
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 538c3bb2..631db28b 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -162,11 +162,6 @@ namespace {
class CodeGenerator_C:
public CodeGenerator
{
- enum class MetadataType {
- None,
- Slice,
- TraitObject,
- };
enum class Mode {
//FullStd,
Gcc, // Use GCC/Clang extensions
@@ -311,6 +306,19 @@ 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)) {"
+ << " int ordering_load = (ordering == memory_order_release || ordering == memory_order_acq_rel ? memory_order_relaxed : ordering);" // If Release, Load with Relaxed
+ << " for(;;) {"
+ << " uint"<<sz<<"_t v = atomic_load_explicit((_Atomic uint"<<sz<<"_t*)slot, ordering_load);"
+ << " if( atomic_compare_exchange_strong_explicit((_Atomic uint"<<sz<<"_t*)slot, &v, cb(v, param), ordering, ordering_load) ) return v;"
+ << " }"
+ << "}\n"
+ ;
+ }
break;
case Compiler::Msvc:
m_of
@@ -408,7 +416,20 @@ namespace {
<< "static inline uint8_t InterlockedExchangeNoFence8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
<< "static inline uint8_t InterlockedExchangeAcquire8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
<< "static inline uint8_t InterlockedExchangeRelease8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
+ << "static inline uint8_t InterlockedCompareExchange32(volatile uint32_t* v, uint32_t n, uint32_t e){ return InterlockedCompareExchange(v, n, e); }\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, uint"<<sz<<"_t (*cb)(uint"<<sz<<"_t, uint"<<sz<<"_t)) {"
+ << " for(;;) {"
+ << " uint"<<sz<<"_t v = InterlockedCompareExchange" << sz << "(slot, 0,0);"
+ << " if( InterlockedCompareExchange" << sz << "(slot, v, cb(v, param)) == v ) return v;"
+ << " }"
+ << "}\n"
+ ;
+ }
break;
}
@@ -567,12 +588,37 @@ 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; return __mrustc_revmap[v>>4]|(__mrustc_revmap[v&15]<<4); }\n"
+ << "static inline uint16_t __mrustc_bitrev16(uint16_t v) { if(v==0) return 0; return ((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; return ((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; return ((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.hi), __mrustc_bitrev64(v.lo) }; 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() {}
- void finalise(bool is_executable, const TransOptions& opt) override
+ void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) override
{
// Emit box drop glue after everything else to avoid definition ordering issues
for(auto& e : m_box_glue_todo)
@@ -580,9 +626,14 @@ namespace {
emit_box_drop_glue( mv$(e.first), *e.second );
}
- // TODO: Define this function in MIR.
- if( is_executable )
+ const bool create_shims = (out_ty == CodegenOutput::Executable);
+
+ // TODO: Support dynamic libraries too
+ // - No main, but has the rest.
+ // - Well... for cdylibs that's the case, for rdylibs it's not
+ if( out_ty == CodegenOutput::Executable )
{
+ // TODO: Define this function in MIR?
m_of << "int main(int argc, const char* argv[]) {\n";
auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start");
if( c_start_path == ::HIR::SimplePath() )
@@ -596,7 +647,11 @@ namespace {
m_of << "\treturn " << Trans_Mangle(::HIR::GenericPath(c_start_path)) << "(argc, argv);\n";
}
m_of << "}\n";
+ }
+ // Auto-generated code/items for the "root" rust binary (cdylib or executable)
+ if( create_shims )
+ {
if( m_compiler == Compiler::Gcc )
{
m_of
@@ -604,6 +659,95 @@ namespace {
<< "__thread void* mrustc_panic_value;\n"
;
}
+
+ // Allocator/panic shims
+ if( TARGETVER_1_29 )
+ {
+ const char* alloc_prefix = "__rdl_";
+ for(size_t i = 0; i < NUM_ALLOCATOR_METHODS; i++)
+ {
+ struct H {
+ static void ty_args(::std::vector<const char*>& out, AllocatorDataTy t) {
+ switch(t)
+ {
+ case AllocatorDataTy::Unit:
+ case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8
+ throw "";
+ // - Args
+ case AllocatorDataTy::Layout: // usize, usize
+ out.push_back("uintptr_t");
+ out.push_back("uintptr_t");
+ break;
+ case AllocatorDataTy::Ptr: // *mut u8
+ out.push_back("int8_t*");
+ break;
+ case AllocatorDataTy::Usize:
+ out.push_back("uintptr_t");
+ break;
+ }
+ }
+ static const char* ty_ret(AllocatorDataTy t) {
+ switch(t)
+ {
+ case AllocatorDataTy::Unit:
+ return "void";
+ case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8
+ return "int8_t*";
+ // - Args
+ case AllocatorDataTy::Layout: // usize, usize
+ case AllocatorDataTy::Ptr: // *mut u8
+ case AllocatorDataTy::Usize:
+ throw "";
+ }
+ throw "";
+ }
+ static void emit_proto(::std::ostream& os, const AllocatorMethod& method, const char* name_prefix, const ::std::vector<const char*>& args) {
+ os << H::ty_ret(method.ret) << " " << name_prefix << method.name << "(";
+ for(size_t j = 0; j < args.size(); j ++)
+ {
+ if( j != 0 )
+ os << ", ";
+ os << args[j] << " a" << j;
+ }
+ os << ")";
+ }
+ };
+ const auto& method = ALLOCATOR_METHODS[i];
+ ::std::vector<const char*> args;
+ for(size_t j = 0; j < method.n_args; j ++)
+ H::ty_args(args, method.args[j]);
+ H::emit_proto(m_of, method, "__rust_", args); m_of << " {\n";
+ m_of << "\textern "; H::emit_proto(m_of, method, alloc_prefix, args); m_of << ";\n";
+ m_of << "\treturn " << alloc_prefix << method.name << "(";
+ for(size_t j = 0; j < args.size(); j ++)
+ {
+ if( j != 0 )
+ m_of << ", ";
+ m_of << "a" << j;
+ }
+ m_of << ");\n";
+ m_of << "}\n";
+ }
+
+ // Bind `panic_impl` lang item to the item tagged with `panic_implementation`
+ m_of << "uint32_t panic_impl(uintptr_t payload) {";
+ const auto& panic_impl_path = m_crate.get_lang_item_path(Span(), "mrustc-panic_implementation");
+ m_of << "extern uint32_t " << Trans_Mangle(panic_impl_path) << "(uintptr_t payload);";
+ m_of << "return " << Trans_Mangle(panic_impl_path) << "(payload);";
+ m_of << "}\n";
+
+ // TODO: Bind `oom` lang item to the item tagged with `alloc_error_handler`
+ // - Can do this in enumerate/auto_impls instead, for better iteraction with enum
+ // XXX: HACK HACK HACK - This only works with libcore/libstd's current layout
+ auto layout_path = ::HIR::SimplePath("core", {"alloc", "Layout"});
+ auto oom_method = ::HIR::SimplePath("std", {"alloc", "rust_oom"});
+ m_of << "struct s_" << Trans_Mangle(layout_path) << "_A { uintptr_t a, b; };\n";
+ m_of << "void oom_impl(struct s_" << Trans_Mangle(layout_path) << "_A l) {"
+ << " extern void " << Trans_Mangle(oom_method) << "(struct s_" << Trans_Mangle(layout_path) << "_A l);"
+ << " " << Trans_Mangle(oom_method) << "(l);"
+ << " }\n"
+ ;
+ }
}
m_of.flush();
@@ -676,14 +820,65 @@ namespace {
{
args.push_back("-g");
}
+ args.push_back("-fPIC");
args.push_back("-o");
- args.push_back(m_outfile_path.c_str());
+ switch(out_ty)
+ {
+ case CodegenOutput::DynamicLibrary:
+ case CodegenOutput::Executable:
+ case CodegenOutput::Object:
+ args.push_back(m_outfile_path .c_str());
+ break;
+ case CodegenOutput::StaticLibrary:
+ args.push_back(m_outfile_path+".o");
+ break;
+ }
args.push_back(m_outfile_path_c.c_str());
- if( is_executable )
+ switch(out_ty)
{
+ case CodegenOutput::DynamicLibrary:
+ args.push_back("-shared");
+ case CodegenOutput::Executable:
for( const auto& crate : m_crate.m_ext_crates )
{
- args.push_back(crate.second.m_path + ".o");
+ auto is_dylib = [](const ::HIR::ExternCrate& c) {
+ bool rv = false;
+ // TODO: Better rule than this
+ rv |= (c.m_path.compare(c.m_path.size() - 3, 3, ".so") == 0);
+ rv |= (c.m_path.compare(c.m_path.size() - 4, 4, ".dll") == 0);
+ return rv;
+ };
+ // If this crate is included in a dylib crate, ignore it
+ bool is_in_dylib = false;
+ for( const auto& crate2 : m_crate.m_ext_crates )
+ {
+ if( is_dylib(crate2.second) )
+ {
+ for(const auto& subcrate : crate2.second.m_data->m_ext_crates)
+ {
+ if( subcrate.second.m_path == crate.second.m_path ) {
+ DEBUG(crate.first << " referenced by dylib " << crate2.first);
+ is_in_dylib = true;
+ }
+ }
+ }
+ if( is_in_dylib )
+ break;
+ }
+ // NOTE: Only exclude non-dylibs referenced by other dylibs
+ if( is_in_dylib && !is_dylib(crate.second) ) {
+ }
+ else if( crate.second.m_path.compare(crate.second.m_path.size() - 5, 5, ".rlib") == 0 ) {
+ args.push_back(crate.second.m_path + ".o");
+ }
+ else if( is_dylib(crate.second) ) {
+ // TODO: Get the dir and base name (strip `lib` and `.so` off)
+ // and emit -L/-Wl,-rpath if that path isn't already emitted.
+ args.push_back(crate.second.m_path);
+ }
+ else {
+ // Proc macro.
+ }
}
for(const auto& path : link_dirs )
{
@@ -708,10 +903,12 @@ namespace {
{
args.push_back( a.c_str() );
}
- }
- else
- {
+ // TODO: Include the HIR file as a magic object?
+ break;
+ case CodegenOutput::StaticLibrary:
+ case CodegenOutput::Object:
args.push_back("-c");
+ break;
}
break;
case Compiler::Msvc:
@@ -738,13 +935,27 @@ namespace {
args.push_back("/DEBUG");
args.push_back("/Zi");
}
- if(is_executable)
+ switch(out_ty)
{
+ case CodegenOutput::Executable:
+ case CodegenOutput::DynamicLibrary:
args.push_back(FMT("/Fe" << m_outfile_path));
+ switch(out_ty)
+ {
+ case CodegenOutput::Executable:
+ args.push_back("/link");
+ break;
+ case CodegenOutput::DynamicLibrary:
+ args.push_back("/LD");
+ break;
+ default:
+ throw "bug";
+ }
+
for( const auto& crate : m_crate.m_ext_crates )
{
- args.push_back(crate.second.m_path + ".o");
+ args.push_back(crate.second.m_path + ".obj");
}
// Crate-specified libraries
for(const auto& lib : m_crate.m_ext_libs) {
@@ -764,18 +975,20 @@ namespace {
}
args.push_back("kernel32.lib"); // Needed for Interlocked*
- args.push_back("/link");
-
// Command-line specified linker search directories
for(const auto& path : link_dirs )
{
args.push_back(FMT("/LIBPATH:" << path));
}
- }
- else
- {
+ break;
+ case CodegenOutput::StaticLibrary:
+ args.push_back("/c");
+ args.push_back(FMT("/Fo" << m_outfile_path << ".obj"));
+ break;
+ case CodegenOutput::Object:
args.push_back("/c");
args.push_back(FMT("/Fo" << m_outfile_path));
+ break;
}
break;
}
@@ -820,8 +1033,45 @@ namespace {
exit(1);
}
}
+
+ // HACK! Static libraries aren't implemented properly yet, just touch the output file
+ if( out_ty == CodegenOutput::StaticLibrary )
+ {
+ ::std::ofstream of( m_outfile_path );
+ if( !of.good() )
+ {
+ // TODO: Error?
+ }
+ }
}
+ void emit_box_drop(unsigned indent_level, const ::HIR::TypeRef& inner_type, const ::MIR::LValue& slot, bool run_destructor)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+ // Emit a call to box_free for the type
+ if( run_destructor )
+ {
+ auto inner_ptr =
+ ::MIR::LValue::new_Field(
+ ::MIR::LValue::new_Field(
+ ::MIR::LValue::new_Field(
+ slot.clone()
+ ,0)
+ ,0)
+ ,0)
+ ;
+ emit_destructor_call( ::MIR::LValue::new_Deref(mv$(inner_ptr)), inner_type, true, indent_level );
+ }
+ // TODO: This is specific to the official liballoc's owned_box
+ ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { inner_type.clone() } };
+ if( TARGETVER_1_29 ) {
+ // In 1.29, `box_free` takes Unique, so pass the Unique within the Box
+ m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0);\n";
+ }
+ else {
+ m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0._0._0);\n";
+ }
+ }
void emit_box_drop_glue(::HIR::GenericPath p, const ::HIR::Struct& item)
{
auto struct_ty = ::HIR::TypeRef( p.clone(), &item );
@@ -841,13 +1091,7 @@ namespace {
m_mir_res = &mir_res;
m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n";
- // Obtain inner pointer
- // TODO: This is very specific to the structure of the official liballoc's Box.
- m_of << "\t"; emit_ctype(args[0].second, FMT_CB(ss, ss << "arg0"; )); m_of << " = rv->_0._0._0;\n";
- // Call destructor of inner data
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true, 1);
- // Emit a call to box_free for the type
- m_of << "\t" << Trans_Mangle(box_free) << "(arg0);\n";
+ emit_box_drop(1, *ity, ::MIR::LValue::new_Deref(::MIR::LValue::new_Return()), /*run_destructor=*/true);
m_of << "}\n";
m_mir_res = nullptr;
@@ -887,6 +1131,9 @@ namespace {
(Struct,
m_of << "struct s_" << Trans_Mangle(te.path) << ";\n";
),
+ (ExternType,
+ m_of << "struct x_" << Trans_Mangle(te.path) << ";\n";
+ ),
(Union,
m_of << "union u_" << Trans_Mangle(te.path) << ";\n";
),
@@ -990,13 +1237,13 @@ namespace {
m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {\n";
if( m_resolve.type_needs_drop_glue(sp, ty) )
{
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& ity : te)
{
// TODO: What if it's a ZST?
emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
- fld_lv.as_Field().field_index ++;
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1034,11 +1281,13 @@ namespace {
::MIR::Function empty_fcn;
::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "struct " << p;), ::HIR::TypeRef(), {}, empty_fcn };
m_mir_res = &top_mir_res;
+ // TODO: repr(transparent) and repr(align(foo))
bool is_packed = item.m_repr == ::HIR::Struct::Repr::Packed;
TRACE_FUNCTION_F(p);
auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item);
const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty);
+ MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << p);
::std::vector<unsigned> fields;
for(const auto& ent : repr->fields)
@@ -1165,7 +1414,15 @@ namespace {
// - Drop Glue
::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> > args;
- if( item.m_markings.has_drop_impl ) {
+ // NOTE: 1.29 has Box impl Drop, but as a no-op - override that here.
+ // - TODO: This override/definition should be done by the caller
+ if( m_resolve.is_type_owned_box(struct_ty) )
+ {
+ m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) );
+ m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
+ return ;
+ }
+ else if( item.m_markings.has_drop_impl ) {
// If the type is defined outside the current crate, define as static (to avoid conflicts when we define it)
if( p.m_path.m_crate_name != m_crate.m_crate_name )
{
@@ -1178,11 +1435,8 @@ namespace {
}
m_of << "void " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
}
- else if( m_resolve.is_type_owned_box(struct_ty) )
- {
- m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) );
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
- return ;
+ else {
+ // No drop impl (magic or no)
}
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, empty_fcn };
@@ -1195,13 +1449,12 @@ namespace {
m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(size_t i = 0; i < repr->fields.size(); i++)
{
- fld_lv.as_Field().field_index = i;
-
emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1);
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1439,14 +1692,14 @@ namespace {
{
m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
if( const auto* e = repr->variants.opt_NonZero() )
{
unsigned idx = 1 - e->zero_variant;
// TODO: Fat pointers?
m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 );
+ emit_destructor_call( ::MIR::LValue::new_Downcast(mv$(self), idx), repr->fields[idx].ty, false, 2 );
m_of << "\t}\n";
}
else if( repr->fields.size() <= 1 )
@@ -1456,15 +1709,15 @@ namespace {
}
else if( const auto* e = repr->variants.opt_Values() )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ auto var_lv =::MIR::LValue::new_Downcast(mv$(self), 0);
m_of << "\tswitch(rv->TAG) {\n";
for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
{
- var_lv.as_Downcast().variant_index = var_idx;
m_of << "\tcase " << e->values[var_idx] << ":\n";
emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2);
m_of << "\t\tbreak;\n";
+ var_lv.inc_Downcast();
}
m_of << "\t}\n";
}
@@ -1621,7 +1874,7 @@ namespace {
// Handled with asm() later
break;
case Compiler::Msvc:
- //m_of << "#pragma comment(linker, \"/alternatename:_" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
+ //m_of << "#pragma comment(linker, \"/alternatename:" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n";
break;
//case Compiler::Std11:
@@ -1710,6 +1963,7 @@ namespace {
TU_MATCHA((te.binding), (pbe),
(Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ),
(Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ),
+ (ExternType, MIR_BUG(*m_mir_res, "Extern type literal " << ty); ),
(Struct,
TU_MATCHA( (pbe->m_data), (se),
(Unit,
@@ -1743,6 +1997,9 @@ namespace {
};
TU_MATCHA( (lit), (e),
(Invalid, m_of << "/* INVALID */"; ),
+ (Defer,
+ MIR_BUG(*m_mir_res, "Defer literal encountered");
+ ),
(List,
m_of << "{";
if( ty.m_data.is_Array() )
@@ -1835,10 +2092,10 @@ namespace {
break;
case ::HIR::CoreType::U64:
case ::HIR::CoreType::Usize:
- m_of << ::std::hex << "0x" << e << ::std::dec;
+ m_of << ::std::hex << "0x" << e << "ull" << ::std::dec;
break;
case ::HIR::CoreType::U128:
- m_of << ::std::hex << "0x" << e << ::std::dec;
+ m_of << ::std::hex << "0x" << e << "ull" << ::std::dec;
break;
case ::HIR::CoreType::I8:
m_of << static_cast<uint16_t>( static_cast<int8_t>(e) );
@@ -1852,7 +2109,7 @@ namespace {
case ::HIR::CoreType::I64:
case ::HIR::CoreType::I128:
case ::HIR::CoreType::Isize:
- m_of << static_cast<int64_t>(e);
+ m_of << static_cast<int64_t>(e) << "ll";
break;
case ::HIR::CoreType::Char:
assert(0 <= e && e <= 0x10FFFF);
@@ -2052,8 +2309,7 @@ namespace {
}
{
- auto vtable_sp = trait_path.m_path;
- vtable_sp.m_components.back() += "#vtable";
+ const auto& vtable_sp = trait.m_vtable_path;
auto vtable_params = trait_path.m_params.clone();
for(const auto& ty : trait.m_type_indexes) {
auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) );
@@ -2089,8 +2345,13 @@ namespace {
{
m_of << "\t""(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ",\n";
}
- m_of << "\t""sizeof("; emit_ctype(type); m_of << "),\n";
- m_of << "\t""ALIGNOF("; emit_ctype(type); m_of << "),\n";
+
+ {
+ size_t size, align;
+ // NOTE: Uses the Size+Align version because that doesn't panic on unsized
+ MIR_ASSERT(*m_mir_res, Target_GetSizeAndAlignOf(sp, m_resolve, type, size, align), "Unexpected generic? " << type);
+ m_of << "\t" << size << ", " << align << ",\n";
+ }
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
@@ -2123,9 +2384,19 @@ namespace {
m_of << "// EXTERN extern \"" << item.m_abi << "\" " << p << "\n";
// For MSVC, make a static wrapper that goes and calls the actual function
- if( item.m_linkage.name != "" && m_compiler == Compiler::Msvc )
+ if( item.m_linkage.name.rfind("llvm.", 0) == 0 )
{
m_of << "static ";
+ emit_function_header(p, item, params);
+ // TODO: Hand off to compiler-specific intrinsics
+ m_of << " { abort(); }\n";
+ m_mir_res = nullptr;
+ return ;
+ }
+ else if( item.m_linkage.name != "" && m_compiler == Compiler::Msvc )
+ {
+ m_of << "#pragma comment(linker, \"/alternatename:" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
+ m_of << "extern ";
}
else if( item.m_linkage.name == "_Unwind_RaiseException" )
{
@@ -2153,48 +2424,6 @@ namespace {
m_of << " asm(\"" << item.m_linkage.name << "\")";
break;
case Compiler::Msvc:
- m_of << " {\n";
- // A few hacky hard-coded signatures
- if( item.m_linkage.name == "SetFilePointerEx" )
- {
- // LARGE_INTEGER
- m_of << "\tLARGE_INTEGER arg1_v;\n";
- m_of << "\targ1_v.QuadPart = arg1;\n";
- m_of << "\treturn SetFilePointerEx(arg0, arg1_v, arg2, arg3);\n";
- }
- else if( item.m_linkage.name == "CopyFileExW" )
- {
- // Not field access to undo an Option<fn()>
- m_of << "\treturn CopyFileExW(arg0, arg1, arg2.DATA.var_1._0, arg3, arg4, arg5);\n";
- }
- // BUG: libtest defines this as returning an i32, but it's void
- else if( item.m_linkage.name == "GetSystemInfo" )
- {
- m_of << "\tGetSystemInfo(arg0);\n";
- m_of << "\treturn 0;\n";
- }
- else
- {
- m_of << "\t";
- if( TU_TEST1(item.m_return.m_data, Tuple, .size() == 0) )
- ;
- else if( item.m_return.m_data.is_Diverge() )
- ;
- else {
- m_of << "return ";
- if( item.m_return.m_data.is_Pointer() )
- m_of << "(void*)";
- }
- m_of << item.m_linkage.name << "(";
- for(size_t i = 0; i < item.m_args.size(); i ++ )
- {
- if( i > 0 )
- m_of << ", ";
- m_of << "arg" << i;
- }
- m_of << ");\n";
- }
- m_of << "}";
break;
}
}
@@ -2212,6 +2441,7 @@ namespace {
m_of << "// PROTO extern \"" << item.m_abi << "\" " << p << "\n";
if( item.m_linkage.name != "" )
{
+ // If this function is implementing an external ABI, just rename it (don't bother with per-compiler trickery).
m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n";
}
if( is_extern_def )
@@ -2693,10 +2923,7 @@ namespace {
// Shallow drops are only valid on owned_box
if( const auto* ity = m_resolve.is_type_owned_box(ty) )
{
- // Emit a call to box_free for the type
- ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } };
- // TODO: This is specific to the official liballoc's owned_box
- m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n";
+ emit_box_drop(1, *ity, e.slot, /*run_destructor=*/false);
}
else
{
@@ -2709,6 +2936,7 @@ namespace {
}
if( e.flag_idx != ~0u )
m_of << indent << "}\n";
+ m_of << indent << "// ^ " << stmt << "\n";
break; }
case ::MIR::Statement::TAG_Asm:
switch(m_compiler)
@@ -2728,14 +2956,14 @@ namespace {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
- if( e.dst.is_Deref() && this->type_is_bad_zst(ty) )
+ if( /*(e.dst.is_Deref() || e.dst.is_Field()) &&*/ this->type_is_bad_zst(ty) )
{
- m_of << "/* ZST deref */";
+ m_of << "/* ZST assign */\n";
break;
}
- TU_MATCHA( (e.src), (ve),
- (Use,
+ TU_MATCH_HDRA( (e.src), {)
+ TU_ARMA(Use, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve);
if( ty == ::HIR::TypeRef::new_diverge() ) {
@@ -2752,13 +2980,13 @@ namespace {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve);
- ),
- (Constant,
+ }
+ TU_ARMA(Constant, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_constant(ve, &e.dst);
- ),
- (SizedArray,
+ }
+ TU_ARMA(SizedArray, ve) {
if( ve.count == 0 ) {
}
else if( ve.count == 1 ) {
@@ -2777,34 +3005,35 @@ namespace {
m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n";
m_of << indent << "\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val);
}
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
bool special = false;
// If the inner value was a deref, just copy the pointer verbatim
- TU_IFLET(::MIR::LValue, ve.val, Deref, le,
+ if( ve.val.is_Deref() )
+ {
emit_lvalue(e.dst);
m_of << " = ";
- emit_lvalue(*le.val);
+ emit_lvalue( ::MIR::LValue::CRef(ve.val).inner_ref() );
special = true;
- )
+ }
// Magic for taking a &-ptr to unsized field of a struct.
// - Needs to get metadata from bottom-level pointer.
- else TU_IFLET(::MIR::LValue, ve.val, Field, le,
+ else if( ve.val.is_Field() ) {
if( metadata_type(ty) != MetadataType::None ) {
- const ::MIR::LValue* base_val = &*le.val;
- while(base_val->is_Field())
- base_val = &*base_val->as_Field().val;
- MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref");
- const ::MIR::LValue& base_ptr = *base_val->as_Deref().val;
+ auto base_val = ::MIR::LValue::CRef(ve.val).inner_ref();
+ while(base_val.is_Field())
+ base_val.try_unwrap();
+ MIR_ASSERT(mir_res, base_val.is_Deref(), "DST access must be via a deref");
+ const auto base_ptr = base_val.inner_ref();
// Construct the new DST
emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n" << indent;
emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val);
special = true;
}
- )
+ }
else {
}
@@ -2813,50 +3042,55 @@ namespace {
if( !special && m_options.disallow_empty_structs && ve.val.is_Field() && this->type_is_bad_zst(ty) )
{
// Work backwards to the first non-ZST field
- const auto* val_fp = &ve.val.as_Field();
- while( val_fp->val->is_Field() )
+ auto val_fp = ::MIR::LValue::CRef(ve.val);
+ assert(val_fp.is_Field());
+ while( val_fp.inner_ref().is_Field() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *val_fp->val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, val_fp.inner_ref());
if( !this->type_is_bad_zst(ty) )
break;
+ val_fp.try_unwrap();
}
+ assert(val_fp.is_Field());
// Here, we have `val_fp` be a LValue::Field that refers to a ZST, but the inner of the field points to a non-ZST or a local
emit_lvalue(e.dst);
m_of << " = ";
// If the index is zero, then the best option is to borrow the source
- if( val_fp->val->is_Downcast() )
+ auto field_inner = val_fp.inner_ref();
+ if( field_inner.is_Downcast() )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val->as_Downcast().val);
+ m_of << "(void*)& "; emit_lvalue(field_inner.inner_ref());
}
- else if( val_fp->field_index == 0 )
+ else if( val_fp.as_Field() == 0 )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
else
{
::HIR::TypeRef tmp;
- auto tmp_lv = ::MIR::LValue::make_Field({ box$(val_fp->val->clone()), val_fp->field_index - 1 });
+ auto tmp_lv = ::MIR::LValue::new_Field( field_inner.clone(), val_fp.as_Field() - 1 );
bool use_parent = false;
for(;;)
{
const auto& ty = mir_res.get_lvalue_type(tmp, tmp_lv);
if( !this->type_is_bad_zst(ty) )
break;
- if( tmp_lv.as_Field().field_index == 0 )
+ auto idx = tmp_lv.as_Field();
+ if( idx == 0 )
{
use_parent = true;
break;
}
- tmp_lv.as_Field().field_index -= 1;
+ tmp_lv.m_wrappers.back() = ::MIR::LValue::Wrapper::new_Field(idx - 1);
}
// Reached index zero, with still ZST
if( use_parent )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
// Use the address after the previous item
else
@@ -2873,11 +3107,11 @@ namespace {
m_of << " = ";
m_of << "& "; emit_lvalue(ve.val);
}
- ),
- (Cast,
+ }
+ TU_ARMA(Cast, ve) {
emit_rvalue_cast(mir_res, e.dst, ve);
- ),
- (BinOp,
+ }
+ TU_ARMA(BinOp, ve) {
emit_lvalue(e.dst);
m_of << " = ";
::HIR::TypeRef tmp, tmp_r;
@@ -3028,8 +3262,8 @@ namespace {
{
m_of << ".lo";
}
- ),
- (UniOp,
+ }
+ TU_ARMA(UniOp, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
@@ -3064,24 +3298,24 @@ namespace {
break;
}
emit_lvalue(ve.val);
- ),
- (DstMeta,
+ }
+ TU_ARMA(DstMeta, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".META";
- ),
- (DstPtr,
+ }
+ TU_ARMA(DstPtr, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".PTR";
- ),
- (MakeDst,
+ }
+ TU_ARMA(MakeDst, ve) {
emit_lvalue(e.dst); m_of << ".PTR = "; emit_param(ve.ptr_val); m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val);
- ),
- (Tuple,
+ }
+ TU_ARMA(Tuple, ve) {
bool has_emitted = false;
for(unsigned int j = 0; j < ve.vals.size(); j ++)
{
@@ -3105,15 +3339,15 @@ namespace {
m_of << "._" << j << " = ";
emit_param(ve.vals[j]);
}
- ),
- (Array,
+ }
+ TU_ARMA(Array, ve) {
for(unsigned int j = 0; j < ve.vals.size(); j ++) {
if( j != 0 ) m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = ";
emit_param(ve.vals[j]);
}
- ),
- (Variant,
+ }
+ TU_ARMA(Variant, ve) {
const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path);
if( tyi.is_Union() )
{
@@ -3170,8 +3404,8 @@ namespace {
{
BUG(mir_res.sp, "Unexpected type in Variant");
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, ve) {
if( ve.vals.empty() )
{
if( m_options.disallow_empty_structs )
@@ -3209,8 +3443,8 @@ namespace {
emit_param(ve.vals[j]);
}
}
- )
- )
+ }
+ }
m_of << ";";
m_of << "\t// " << e.dst << " = " << e.src;
m_of << "\n";
@@ -3577,6 +3811,11 @@ namespace {
{
omit_assign = true;
}
+
+ if( this->type_is_bad_zst( m_mir_res->get_lvalue_type(tmp, e.ret_val) ) )
+ {
+ omit_assign = true;
+ }
}
TU_MATCHA( (e.fcn), (e2),
@@ -3775,41 +4014,133 @@ namespace {
{
auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) };
- if( e.tpl == "fnstcw $0" )
+ struct H {
+ static bool check_list(const std::vector<std::pair<std::string, MIR::LValue>>& have, const ::std::initializer_list<const char*>& exp)
+ {
+ if( have.size() != exp.size() )
+ return false;
+ auto h_it = have.begin();
+ auto e_it = exp.begin();
+ for(; h_it != have.end(); ++ h_it, ++e_it)
+ {
+ if( h_it->first != *e_it )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ auto matches_template = [&e,&mir_res](const char* tpl, ::std::initializer_list<const char*> inputs, ::std::initializer_list<const char*> outputs)->bool {
+ if( e.tpl == tpl )
+ {
+ if( !H::check_list(e.inputs, inputs) || !H::check_list(e.outputs, outputs) )
+ {
+ MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
+ }
+ return true;
+ }
+ return false;
+ };
+
+ if( matches_template("fnstcw $0", /*input=*/{}, /*output=*/{"*m"}) )
{
// HARD CODE: `fnstcw` -> _control87
- if( !(e.inputs.size() == 0 && e.outputs.size() == 1 && e.outputs[0].first == "=*m") )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "*("; emit_lvalue(e.outputs[0].second); m_of << ") = _control87(0,0);\n";
return ;
}
- else if( e.tpl == "fldcw $0" )
+ else if( matches_template("fldcw $0", /*input=*/{"m"}, /*output=*/{}) )
{
// HARD CODE: `fldcw` -> _control87
- if( !(e.inputs.size() == 1 && e.inputs[0].first == "m" && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "_control87("; emit_lvalue(e.inputs[0].second); m_of << ", 0xFFFF);\n";
return ;
}
- else if( e.tpl == "int $$0x29" )
+ else if( matches_template("int $$0x29", /*input=*/{"{ecx}"}, /*output=*/{}) )
{
- if( !(e.inputs.size() == 1 && e.inputs[0].first == "{ecx}" && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "__fastfail("; emit_lvalue(e.inputs[0].second); m_of << ");\n";
return ;
}
- else if( e.tpl == "pause" )
+ else if( matches_template("pause", /*input=*/{}, /*output=*/{}) )
{
- if( !(e.inputs.size() == 0 && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "_mm_pause();\n";
return ;
}
+ else if( matches_template("cpuid\n", /*input=*/{"{eax}", "{ecx}"}, /*output=*/{"={eax}", "={ebx}", "={ecx}", "={edx}"}) )
+ {
+ m_of << indent << "{";
+ m_of << " int cpuid_out[4];";
+ m_of << " __cpuidex(cpuid_out, "; emit_lvalue(e.inputs[0].second); m_of << ", "; emit_lvalue(e.inputs[1].second); m_of << ");";
+ m_of << " "; emit_lvalue(e.outputs[0].second); m_of << " = cpuid_out[0];";
+ m_of << " "; emit_lvalue(e.outputs[1].second); m_of << " = cpuid_out[1];";
+ m_of << " "; emit_lvalue(e.outputs[2].second); m_of << " = cpuid_out[2];";
+ m_of << " "; emit_lvalue(e.outputs[3].second); m_of << " = cpuid_out[3];";
+ m_of << " }\n";
+ return ;
+ }
+ else if( matches_template("pushfq; popq $0", /*input=*/{}, /*output=*/{"=r"}) )
+ {
+ m_of << indent; emit_lvalue(e.outputs[0].second); m_of << " = __readeflags();\n";
+ return ;
+ }
+ else if( matches_template("pushq $0; popfq", /*input=*/{"r"}, /*output=*/{}) )
+ {
+ m_of << indent << "__writeeflags("; emit_lvalue(e.inputs[0].second); m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xgetbv", /*input=*/{"{ecx}"}, /*output=*/{"={eax}", "={edx}"}) )
+ {
+ m_of << indent << "{";
+ m_of << " unsigned __int64 v = _xgetbv("; emit_lvalue(e.inputs[0].second); m_of << ");";
+ m_of << " "; emit_lvalue(e.outputs[0].second); m_of << " = (uint32_t)(v & 0xFFFFFFFF);";
+ m_of << " "; emit_lvalue(e.outputs[1].second); m_of << " = (uint32_t)(v >> 32);";
+ m_of << " }\n";
+ return ;
+ }
+ // parking_lot src/elision.rs
+ else if( matches_template("xacquire; lock; cmpxchgl $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchangeAcquire(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xrelease; lock; cmpxchgl $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchangeRelease(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xacquire; lock; cmpxchgq $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchange64Acquire(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xrelease; lock; cmpxchgq $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchange64Release(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
else
{
// No hard-coded translations.
}
+ if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
+ MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
+ }
if( !e.inputs.empty() || !e.outputs.empty() )
{
MIR_TODO(mir_res, "Inputs/outputs in msvc inline assembly - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
@@ -3823,9 +4154,6 @@ namespace {
#endif
}
- if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
- MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
- }
m_of << indent << "__asm {\n";
m_of << indent << "\t";
@@ -3914,7 +4242,7 @@ namespace {
}
}
- void emit_intrinsic_call(const ::std::string& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e)
+ void emit_intrinsic_call(const RcString& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e)
{
const auto& mir_res = *m_mir_res;
enum class Ordering
@@ -3947,7 +4275,7 @@ namespace {
}
throw "";
};
- auto get_atomic_ordering = [&](const ::std::string& name, size_t prefix_len)->Ordering {
+ auto get_atomic_ordering = [&](const RcString& name, size_t prefix_len)->Ordering {
if( name.size() < prefix_len )
{
return Ordering::SeqCst;
@@ -4112,11 +4440,14 @@ namespace {
}
};
if( name == "size_of" ) {
- emit_lvalue(e.ret_val); m_of << " = sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ size_t size = 0;
+ MIR_ASSERT(mir_res, Target_GetSizeOf(sp, m_resolve, params.m_types.at(0), size), "Can't get size of " << params.m_types.at(0));
+ emit_lvalue(e.ret_val); m_of << " = " << size;
}
- else if( name == "min_align_of" ) {
- //emit_lvalue(e.ret_val); m_of << " = alignof("; emit_ctype(params.m_types.at(0)); m_of << ")";
- emit_lvalue(e.ret_val); m_of << " = ALIGNOF("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ else if( name == "min_align_of" || name == "align_of" ) {
+ size_t align = 0;
+ MIR_ASSERT(mir_res, Target_GetAlignOf(sp, m_resolve, params.m_types.at(0), align), "Can't get alignment of " << params.m_types.at(0));
+ emit_lvalue(e.ret_val); m_of << " = " << align;
}
else if( name == "size_of_val" ) {
emit_lvalue(e.ret_val); m_of << " = ";
@@ -4124,6 +4455,7 @@ namespace {
//TODO: Get the unsized type and use that in place of MetadataType
auto inner_ty = get_inner_unsized_type(ty);
if( inner_ty == ::HIR::TypeRef() ) {
+ // TODO: Target_GetSizeOf
m_of << "sizeof("; emit_ctype(ty); m_of << ")";
}
else if( const auto* te = inner_ty.m_data.opt_Slice() ) {
@@ -4216,8 +4548,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) )
{
@@ -4225,7 +4557,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 << "}";
}
@@ -4244,7 +4576,9 @@ namespace {
emit_lvalue(e.ret_val); m_of << ".META = ";
switch(dst_meta)
{
+ case MetadataType::Unknown: assert(!"Impossible");
case MetadataType::None: assert(!"Impossible");
+ case MetadataType::Zero: assert(!"Impossible");
case MetadataType::Slice: m_of << "(size_t)"; break;
case MetadataType::TraitObject: m_of << "(const void*)"; break;
}
@@ -4257,7 +4591,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" ) {
@@ -4277,6 +4611,7 @@ namespace {
m_of << ", "; emit_param(e.args.at(2)); m_of << " * sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")";
m_of << ")";
}
+ // NOTE: This is generic, and fills count*sizeof(T) (unlike memset)
else if( name == "write_bytes" ) {
if( this->type_is_bad_zst(params.m_types.at(0)) ) {
m_of << "/* zst */";
@@ -4292,7 +4627,7 @@ namespace {
// Nothing needs to be done, this just stops the destructor from running.
}
else if( name == "drop_in_place" ) {
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(e.args.at(0).as_LValue().clone()) }), params.m_types.at(0), true, 1 /* TODO: get from caller */ );
+ emit_destructor_call( ::MIR::LValue::new_Deref(e.args.at(0).as_LValue().clone()), params.m_types.at(0), true, /*indent_level=*/1 /* TODO: get from caller */ );
}
else if( name == "needs_drop" ) {
// Returns `true` if the actual type given as `T` requires drop glue;
@@ -4329,7 +4664,7 @@ namespace {
{
case Compiler::Gcc:
m_of << "{ ";
- m_of << " jmp_buf jmpbuf; mrustc_panic_target = &jmpbuf;";
+ m_of << " jmp_buf jmpbuf, *old = mrustc_panic_target; mrustc_panic_target = &jmpbuf;";
m_of << " if(setjmp(jmpbuf)) {";
// NOTE: gcc unwind has a pointer as its `local_ptr` parameter
m_of << " *(void**)("; emit_param(e.args.at(2)); m_of << ") = mrustc_panic_value;";
@@ -4347,7 +4682,8 @@ namespace {
case Compiler::Gcc:
m_of << ";";
m_of << " }";
- m_of << " mrustc_panic_target = NULL;";
+ m_of << " if(mrustc_panic_target != &jmpbuf) { abort(); }";
+ m_of << " mrustc_panic_target = old;";
m_of << " }";
break;
default:
@@ -4417,6 +4753,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);
@@ -4623,7 +4975,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)) )
{
@@ -4696,7 +5049,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 << " = (";
@@ -4828,6 +5181,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 ) {
@@ -4842,6 +5200,18 @@ 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));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __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);
@@ -4850,6 +5220,34 @@ 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.c_str()[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));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __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.c_str()[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));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __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 << " = ";
@@ -4872,11 +5270,7 @@ namespace {
m_of << "atomic_store_explicit("; emit_atomic_cast(); emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ")";
break;
case Compiler::Msvc:
- emit_msvc_atomic_op("InterlockedCompareExchange", ordering, true); emit_param(e.args.at(0)); m_of << ", ";
- emit_param(e.args.at(1));
- m_of << ", ";
- emit_param(e.args.at(1));
- m_of << ")";
+ m_of << "*"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1));
break;
}
}
@@ -4960,6 +5354,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 << "'");
}
@@ -4994,7 +5393,7 @@ namespace {
if( te.type == ::HIR::BorrowType::Owned )
{
// Call drop glue on inner.
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true, indent_level );
+ emit_destructor_call( ::MIR::LValue::new_Deref(slot.clone()), *te.inner, true, indent_level );
}
),
(Path,
@@ -5004,15 +5403,14 @@ namespace {
const char* make_fcn = nullptr;
switch( metadata_type(ty) )
{
+ case MetadataType::Unknown:
+ MIR_BUG(*m_mir_res, ty << " unknown metadata");
case MetadataType::None:
-
+ case MetadataType::Zero:
if( this->type_is_bad_zst(ty) && (slot.is_Field() || slot.is_Downcast()) )
{
m_of << indent << Trans_Mangle(p) << "((void*)&";
- if( slot.is_Field() )
- emit_lvalue(*slot.as_Field().val);
- else
- emit_lvalue(*slot.as_Downcast().val);
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref());
m_of << ");\n";
}
else
@@ -5027,7 +5425,7 @@ namespace {
m_of << indent << Trans_Mangle(p) << "( " << make_fcn << "(";
if( slot.is_Deref() )
{
- emit_lvalue(*slot.as_Deref().val);
+ emit_lvalue( ::MIR::LValue::CRef(slot).inner_ref() );
m_of << ".PTR";
}
else
@@ -5035,10 +5433,10 @@ namespace {
m_of << "&"; emit_lvalue(slot);
}
m_of << ", ";
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- emit_lvalue(*lvp->as_Deref().val); m_of << ".META";
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ emit_lvalue(lvr.inner_ref()); m_of << ".META";
m_of << ") );\n";
break;
}
@@ -5048,7 +5446,7 @@ namespace {
if( te.size_val > 0 )
{
m_of << indent << "for(unsigned i = 0; i < " << te.size_val << "; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
}
),
@@ -5056,24 +5454,24 @@ namespace {
// Emit destructors for all entries
if( te.size() > 0 )
{
- ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 });
+ ::MIR::LValue lv = ::MIR::LValue::new_Field(slot.clone(), 0);
for(unsigned int i = 0; i < te.size(); i ++)
{
- lv.as_Field().field_index = i;
emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1), indent_level);
+ lv.inc_Field();
}
}
),
(TraitObject,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping TraitObject without a pointer");
// Call destructor in vtable
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop(";
- if( const auto* ve = slot.opt_Deref() )
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(lvr.inner_ref()); m_of << ".META)->drop(";
+ if( slot.is_Deref() )
{
- emit_lvalue(*ve->val); m_of << ".PTR";
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref()); m_of << ".PTR";
}
else
{
@@ -5083,12 +5481,12 @@ namespace {
),
(Slice,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping Slice without a pointer");
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
// Call destructor on all entries
- m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(lvr.inner_ref()); m_of << ".META; i++) {\n";
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
)
)
@@ -5100,8 +5498,22 @@ namespace {
auto v = m_resolve.get_value(m_mir_res->sp, path, params);
if( const auto* e = v.opt_Constant() )
{
- ty = params.monomorph(m_mir_res->sp, (*e)->m_type);
- return (*e)->m_value_res;
+ const auto& hir_const = **e;
+ ty = params.monomorph(m_mir_res->sp, hir_const.m_type);
+ if( hir_const.m_value_res.is_Defer() )
+ {
+ // Do some form of lookup of a pre-cached evaluated monomorphised constant
+ // - Maybe on the `Constant` entry there can be a list of pre-monomorphised values
+ auto it = hir_const.m_monomorph_cache.find(path);
+ if( it == hir_const.m_monomorph_cache.end() )
+ {
+ MIR_BUG(*m_mir_res, "Constant with Defer literal and no cached monomorphisation - " << path);
+ // TODO: Can do the consteval here?
+ }
+ MIR_ASSERT(*m_mir_res, !it->second.is_Defer(), "get_literal_for_const - Cached literal was Defer - " << path);
+ return it->second;
+ }
+ return hir_const.m_value_res;
}
else
{
@@ -5146,7 +5558,7 @@ namespace {
void assign_from_literal(::std::function<void()> emit_dst, const ::HIR::TypeRef& ty, const ::HIR::Literal& lit)
{
- //TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit);
+ TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit);
Span sp;
::HIR::TypeRef tmp;
auto monomorph_with = [&](const ::HIR::PathParams& pp, const ::HIR::TypeRef& ty)->const ::HIR::TypeRef& {
@@ -5168,6 +5580,9 @@ namespace {
TU_MATCHA((te.binding), (pbe),
(Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ),
(Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ),
+ (ExternType,
+ MIR_BUG(*m_mir_res, "Extern type literal");
+ ),
(Struct,
TU_MATCHA( (pbe->m_data), (se),
(Unit,
@@ -5203,6 +5618,9 @@ namespace {
(Invalid,
m_of << "/* INVALID */";
),
+ (Defer,
+ MIR_BUG(*m_mir_res, "Defer literal encountered");
+ ),
(List,
if( ty.m_data.is_Array() )
{
@@ -5276,7 +5694,10 @@ namespace {
const auto& ity = *ty.m_data.as_Borrow().inner;
switch( metadata_type(ity) )
{
+ case MetadataType::Unknown:
+ MIR_BUG(*m_mir_res, ity << " - Unknown meta");
case MetadataType::None:
+ case MetadataType::Zero:
emit_dst(); m_of << " = &" << Trans_Mangle(e);
break;
case MetadataType::Slice:
@@ -5313,116 +5734,125 @@ namespace {
)
}
- void emit_lvalue(const ::MIR::LValue& val) {
- TU_MATCHA( (val), (e),
- (Return,
+ void emit_lvalue(const ::MIR::LValue::CRef& val)
+ {
+ TU_MATCH_HDRA( (val), {)
+ TU_ARMA(Return, _e) {
m_of << "rv";
- ),
- (Argument,
- m_of << "arg" << e.idx;
- ),
- (Local,
- if( e == ~0u )
+ }
+ TU_ARMA(Argument, e) {
+ m_of << "arg" << e;
+ }
+ TU_ARMA(Local, e) {
+ if( e == ::MIR::LValue::Storage::MAX_ARG )
m_of << "i";
else
m_of << "var" << e;
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
m_of << Trans_Mangle(e);
- ),
- (Field,
+ }
+ TU_ARMA(Field, field_index) {
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ auto inner = val.inner_ref();
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ if( ty.m_data.is_Slice() )
+ {
+ if( inner.is_Deref() )
{
m_of << "(("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR)";
}
else
{
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
- m_of << "[" << e.field_index << "]";
+ m_of << "[" << field_index << "]";
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
- m_of << ".DATA[" << e.field_index << "]";
+ emit_lvalue(inner);
+ m_of << ".DATA[" << field_index << "]";
}
- else if( e.val->is_Deref() ) {
+ else if( inner.is_Deref() ) {
auto dst_type = metadata_type(ty);
if( dst_type != MetadataType::None )
{
- m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(*e.val->as_Deref().val); m_of << ".PTR)->_" << e.field_index;
+ m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(inner.inner_ref()); m_of << ".PTR)->_" << field_index;
}
else
{
- emit_lvalue(*e.val->as_Deref().val);
- m_of << "->_" << e.field_index;
+ emit_lvalue(inner.inner_ref());
+ m_of << "->_" << field_index;
}
}
else {
- emit_lvalue(*e.val);
- m_of << "._" << e.field_index;
+ emit_lvalue(inner);
+ m_of << "._" << field_index;
}
- ),
- (Deref,
- // TODO: If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
+ }
+ TU_ARMA(Deref, _e) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
const auto& ty = m_mir_res->get_lvalue_type(tmp, val);
auto dst_type = metadata_type(ty);
+ // If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
if( dst_type != MetadataType::None )
{
m_of << "(*("; emit_ctype(ty); m_of << "*)";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".PTR)";
}
else
{
m_of << "(*";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ")";
}
- ),
- (Index,
+ }
+ TU_ARMA(Index, index_local) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
m_of << "(";
if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ if( inner.is_Deref() )
{
m_of << "("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".DATA";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
m_of << ")[";
- emit_lvalue(*e.idx);
+ emit_lvalue(::MIR::LValue::new_Local(index_local));
m_of << "]";
- ),
- (Downcast,
+ }
+ TU_ARMA(Downcast, variant_index) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- emit_lvalue(*e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ emit_lvalue(inner);
MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
if( ty.m_data.as_Path().binding.is_Enum() )
{
m_of << ".DATA";
}
- m_of << ".var_" << e.variant_index;
- )
- )
+ m_of << ".var_" << variant_index;
+ }
+ }
+ }
+ void emit_lvalue(const ::MIR::LValue& val) {
+ emit_lvalue( ::MIR::LValue::CRef(val) );
}
void emit_constant(const ::MIR::Constant& ve, const ::MIR::LValue* dst_ptr=nullptr)
{
@@ -5443,6 +5873,16 @@ namespace {
{
switch(c.t)
{
+ // TODO: These should already have been truncated/reinterpreted, but just in case.
+ case ::HIR::CoreType::I8:
+ m_of << static_cast<int>( static_cast<int8_t>(c.v) ); // cast to int, because `int8_t` is printed as a `char`
+ break;
+ case ::HIR::CoreType::I16:
+ m_of << static_cast<int16_t>(c.v);
+ break;
+ case ::HIR::CoreType::I32:
+ m_of << static_cast<int32_t>(c.v);
+ break;
case ::HIR::CoreType::I64:
case ::HIR::CoreType::Isize:
m_of << c.v;
@@ -5455,6 +5895,7 @@ namespace {
}
else
{
+ m_of << "(int128_t)";
m_of << c.v;
m_of << "ll";
}
@@ -5488,6 +5929,7 @@ namespace {
}
else
{
+ m_of << "(uint128_t)";
m_of << ::std::hex << "0x" << c.v << "ull" << ::std::dec;
}
break;
@@ -5524,11 +5966,17 @@ namespace {
(Const,
// 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())
+ const auto& lit = get_literal_for_const(*c.p, ty);
+ 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
@@ -5539,7 +5987,7 @@ namespace {
}
),
(ItemAddr,
- TU_MATCHA( (c.m_data), (pe),
+ TU_MATCHA( (c->m_data), (pe),
(Generic,
if( pe.m_path.m_components.size() > 1 && m_crate.get_typeitem_by_path(sp, pe.m_path, false, true).is_Enum() )
;
@@ -5556,7 +6004,7 @@ namespace {
}
),
(UfcsUnknown,
- MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << c);
+ MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << *c);
),
(UfcsInherent,
// TODO: If the target is a function, don't emit the &
@@ -5567,7 +6015,7 @@ namespace {
m_of << "&";
)
)
- m_of << Trans_Mangle(c);
+ m_of << Trans_Mangle(*c);
)
)
}
@@ -5633,6 +6081,10 @@ namespace {
(Enum,
m_of << "struct e_" << Trans_Mangle(te.path);
),
+ (ExternType,
+ //m_of << "struct x_" << Trans_Mangle(te.path);
+ return ;
+ ),
(Unbound,
MIR_BUG(*m_mir_res, "Unbound type path in trans - " << ty);
),
@@ -5741,61 +6193,9 @@ namespace {
return ::HIR::TypeRef();
}
}
- // TODO: Move this to a more common location
- MetadataType metadata_type(const ::HIR::TypeRef& ty) const
- {
- if( ty == ::HIR::CoreType::Str || ty.m_data.is_Slice() ) {
- return MetadataType::Slice;
- }
- else if( ty.m_data.is_TraitObject() ) {
- return MetadataType::TraitObject;
- }
- else if( ty.m_data.is_Path() )
- {
- TU_MATCH_DEF( ::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (tpb),
- (
- MIR_BUG(*m_mir_res, "Unbound/opaque path in trans - " << ty);
- ),
- (Struct,
- switch( tpb->m_struct_markings.dst_type )
- {
- case ::HIR::StructMarkings::DstType::None:
- return MetadataType::None;
- case ::HIR::StructMarkings::DstType::Possible: {
- // TODO: How to figure out? Lazy way is to check the monomorpised type of the last field (structs only)
- const auto& path = ty.m_data.as_Path().path.m_data.as_Generic();
- const auto& str = *ty.m_data.as_Path().binding.as_Struct();
- auto monomorph = [&](const auto& tpl) {
- auto rv = monomorphise_type(sp, str.m_params, path.m_params, tpl);
- m_resolve.expand_associated_types(sp, rv);
- return rv;
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit, MIR_BUG(*m_mir_res, "Unit-like struct with DstType::Possible"); ),
- (Tuple, return metadata_type( monomorph(se.back().ent) ); ),
- (Named, return metadata_type( monomorph(se.back().second.ent) ); )
- )
- //MIR_TODO(*m_mir_res, "Determine DST type when ::Possible - " << ty);
- return MetadataType::None;
- }
- case ::HIR::StructMarkings::DstType::Slice:
- return MetadataType::Slice;
- case ::HIR::StructMarkings::DstType::TraitObject:
- return MetadataType::TraitObject;
- }
- ),
- (Union,
- return MetadataType::None;
- ),
- (Enum,
- return MetadataType::None;
- )
- )
- throw "";
- }
- else {
- return MetadataType::None;
- }
+
+ MetadataType metadata_type(const ::HIR::TypeRef& ty) const {
+ return m_resolve.metadata_type(m_mir_res ? m_mir_res->sp : sp, ty);
}
void emit_ctype_ptr(const ::HIR::TypeRef& inner_ty, ::FmtLambda inner) {
@@ -5804,9 +6204,12 @@ namespace {
//}
//else
{
- switch( metadata_type(inner_ty) )
+ switch( this->metadata_type(inner_ty) )
{
+ case MetadataType::Unknown:
+ BUG(sp, inner_ty << " unknown metadata type");
case MetadataType::None:
+ case MetadataType::Zero:
emit_ctype(inner_ty, FMT_CB(ss, ss << "*" << inner;));
break;
case MetadataType::Slice:
@@ -5821,7 +6224,7 @@ namespace {
bool is_dst(const ::HIR::TypeRef& ty) const
{
- return metadata_type(ty) != MetadataType::None;
+ return this->metadata_type(ty) != MetadataType::None;
}
};
Span CodeGenerator_C::sp;
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp
index 73de19d3..58739805 100644
--- a/src/trans/codegen_mmir.cpp
+++ b/src/trans/codegen_mmir.cpp
@@ -18,6 +18,8 @@
namespace
{
+ size_t PTR_BASE = 0x1000; // See matching value in standalone_miri value.hpp
+
size_t Target_GetSizeOf_Required(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
{
size_t size;
@@ -39,47 +41,51 @@ namespace
::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::LValue>& x)
{
- auto fmt_lhs = [](::std::ostream& os, const ::MIR::LValue& lv) {
- if( lv.is_Deref() ) {
- os << "(" << fmt(lv) << ")";
- }
- else {
- os << fmt(lv);
- }
- };
- switch(x.e.tag())
+ for(const auto& w : ::reverse(x.e.m_wrappers))
{
- case ::MIR::LValue::TAGDEAD: throw "";
- TU_ARM(x.e, Return, _e) (void)_e;
+ if( w.is_Deref() ) {
+ os << "(*";
+ }
+ }
+ TU_MATCHA( (x.e.m_root), (e),
+ (Return,
os << "RETURN";
- break;
- TU_ARM(x.e, Local, e)
+ ),
+ (Local,
os << "var" << e;
- break;
- TU_ARM(x.e, Argument, e)
- os << "arg" << e.idx;
- break;
- TU_ARM(x.e, Static, e)
+ ),
+ (Argument,
+ os << "arg" << e;
+ ),
+ (Static,
os << e;
- break;
- TU_ARM(x.e, Deref, e)
- os << "*" << fmt(*e.val);
- break;
- TU_ARM(x.e, Field, e) {
- fmt_lhs(os, *e.val);
- // Avoid `0.` existing in the output
- if( e.val->is_Field() || e.val->is_Downcast() )
- os << " ";
- os << "." << e.field_index;
- } break;
- TU_ARM(x.e, Index, e) {
- fmt_lhs(os, *e.val);
- os << "[" << fmt(*e.idx) << "]";
- } break;
- TU_ARM(x.e, Downcast, e) {
- fmt_lhs(os, *e.val);
- os << "@" << e.variant_index;
- } break;
+ )
+ )
+ bool was_num = false;
+ for(const auto& w : x.e.m_wrappers)
+ {
+ bool prev_was_num = was_num; was_num = false;
+ switch(w.tag())
+ {
+ case ::MIR::LValue::Wrapper::TAGDEAD: throw "";
+ TU_ARM(w, Deref, e)
+ os << ")";
+ break;
+ TU_ARM(w, Field, field_index) {
+ // Add a space to prevent accidental float literals
+ if( prev_was_num )
+ os << " ";
+ os << "." << field_index;
+ was_num = true;
+ } break;
+ TU_ARM(w, Index, e) {
+ os << "[" << fmt(::MIR::LValue::new_Local(e)) << "]";
+ } break;
+ TU_ARM(w, Downcast, variant_index) {
+ os << "@" << variant_index;
+ was_num = true;
+ } break;
+ }
}
return os;
}
@@ -112,7 +118,10 @@ namespace
os << " " << v.t;
} break;
TU_ARM(e, ItemAddr, v) {
- os << "ADDROF " << v;
+ os << "ADDROF " << *v;
+ } break;
+ TU_ARM(e, Const, v) {
+ BUG(Span(), "Stray named constant in MIR after cleanup - " << e);
} break;
default:
os << e;
@@ -158,18 +167,18 @@ namespace
CodeGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile):
m_crate(crate),
m_resolve(crate),
- m_outfile_path(outfile + ".mir"),
- m_of(m_outfile_path)
+ m_outfile_path(outfile),
+ m_of(m_outfile_path + ".mir")
{
for( const auto& crate : m_crate.m_ext_crates )
{
- m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".o.mir\";\n";
+ m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".mir\";\n";
}
}
- void finalise(bool is_executable, const TransOptions& opt) override
+ void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) override
{
- if( is_executable )
+ if( out_ty == CodegenOutput::Executable )
{
m_of << "fn ::main#(isize, *const *const i8): isize {\n";
auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start");
@@ -190,10 +199,33 @@ namespace
m_of << "\t\tRETURN\n";
m_of << "\t}\n";
m_of << "}\n";
+
+ {
+ // Bind `panic_impl` lang item to the item tagged with `panic_implementation`
+ const auto& panic_impl_path = m_crate.get_lang_item_path(Span(), "mrustc-panic_implementation");
+ m_of << "fn ::panic_impl#(usize): u32 = \"panic_impl\":\"Rust\" {\n";
+ m_of << "\t0: {\n";
+ m_of << "\t\tCALL RETURN = " << panic_impl_path << "(arg0) goto 1 else 2\n";
+ m_of << "\t}\n";
+ m_of << "\t1: { RETURN }\n";
+ m_of << "\t2: { DIVERGE }\n";
+ m_of << "}\n";
+
+ // TODO: OOM impl?
+ }
}
m_of.flush();
m_of.close();
+
+ // HACK! Create the output file, but keep it empty
+ {
+ ::std::ofstream of( m_outfile_path );
+ if( !of.good() )
+ {
+ // TODO: Error?
+ }
+ }
}
@@ -233,14 +265,14 @@ namespace
m_of << "\t0: {\n";
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
m_of << "\t\t""RETURN\n";
m_of << "\t}\n";
@@ -336,9 +368,9 @@ namespace
const auto& te = t.m_data.as_TraitObject();
//auto vtp = t.m_data.as_TraitObject().m_trait.m_path;
- auto vtable_gp = te.m_trait.m_path.clone();
- vtable_gp.m_path.m_components.back() += "#vtable";
const auto& trait = resolve.m_crate.get_trait_by_path(sp, te.m_trait.m_path.m_path);
+ auto vtable_gp = ::HIR::GenericPath(trait.m_vtable_path);
+ vtable_gp.m_params = te.m_trait.m_path.m_params.clone();
vtable_gp.m_params.m_types.resize( vtable_gp.m_params.m_types.size() + trait.m_type_indexes.size() );
for(const auto& ty : trait.m_type_indexes) {
auto aty = te.m_trait.m_type_bounds.at(ty.first).clone();
@@ -364,8 +396,8 @@ namespace
};
- // TODO: Generate the drop glue (and determine if there is any)
- bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ // Generate the drop glue (and determine if there is any)
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << ty);
@@ -396,13 +428,13 @@ namespace
//ASSERT_BUG(sp, !item.m_markings.has_drop_impl, "Box shouldn't have a Drop impl");
// TODO: This is very specific to the structure of the official liballoc's Box.
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_p_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_p_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
if( m_resolve.type_needs_drop_glue(sp, *ity) ) {
- auto fld_lv = ::MIR::LValue::make_Deref({ box$(fld_p_lv.clone()) });
+ auto fld_lv = ::MIR::LValue::new_Deref( fld_p_lv.clone() );
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
@@ -432,14 +464,14 @@ namespace
m_of << "\t2: {\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
}
m_of << "\t\t""RETURN\n";
@@ -448,6 +480,51 @@ namespace
}
m_mir_res = nullptr;
}
+ virtual void emit_constructor_enum(const Span& sp, const ::HIR::GenericPath& var_path, const ::HIR::Enum& item, size_t var_idx)
+ {
+ TRACE_FUNCTION_F(var_path);
+
+ ::HIR::TypeRef tmp;
+ auto monomorph = [&](const auto& x)->const auto& {
+ if( monomorphise_type_needed(x) ) {
+ tmp = monomorphise_type(sp, item.m_params, var_path.m_params, x);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return x;
+ }
+ };
+
+ auto enum_path = var_path.clone();
+ enum_path.m_path.m_components.pop_back();
+
+ // Create constructor function
+ const auto& var_ty = item.m_data.as_Data().at(var_idx).type;
+ const auto& e = var_ty.m_data.as_Path().binding.as_Struct()->m_data.as_Tuple();
+ m_of << "fn " << var_path << "(";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << monomorph(e[i].ent);
+ }
+ m_of << "): " << enum_path << " {\n";
+ m_of << "\tlet var0: " << monomorph(var_ty) << ";\n";
+ m_of << "\t0: {\n";
+ m_of << "\t\tASSIGN var0 = { ";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << "arg" << i;
+ }
+ m_of << " }: " << monomorph(var_ty) << ";\n";
+ m_of << "\t\tASSIGN RETURN = VARIANT " << enum_path << " " << var_idx << " var0;\n";
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ m_of << "}";
+ }
void emit_constructor_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override
{
TRACE_FUNCTION_F(p);
@@ -462,7 +539,7 @@ namespace
return x;
}
};
- // Crate constructor function
+ // Create constructor function
const auto& e = item.m_data.as_Tuple();
m_of << "fn " << p << "(";
for(unsigned int i = 0; i < e.size(); i ++)
@@ -494,10 +571,17 @@ namespace
TRACE_FUNCTION_F(p);
::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item);
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ auto drop_glue_path = ::HIR::Path(ty.clone(), "drop_glue#");
+
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for union " << ty);
m_of << "type " << p << " {\n";
m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n";
+ if( has_drop_glue )
+ {
+ m_of << "\tDROP " << drop_glue_path << ";\n";
+ }
for(const auto& e : repr->fields)
{
m_of << "\t" << e.offset << " = " << e.ty << ";\n";
@@ -508,28 +592,28 @@ namespace
}
m_of << "}\n";
- // TODO: Drop glue!
-#if 0
- // Drop glue (calls destructor if there is one)
- auto item_ty = ::HIR::TypeRef(p.clone(), &item);
- auto drop_glue_path = ::HIR::Path(item_ty.clone(), "#drop_glue");
- auto item_ptr_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, item_ty.clone());
- auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(item_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath()));
- ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), item_ptr_ty, {}, empty_fcn };
- m_mir_res = &mir_res;
-
- if( item.m_markings.has_drop_impl )
- {
- m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(union u_" << Trans_Mangle(p) << "*rv);\n";
- }
-
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "(union u_" << Trans_Mangle(p) << "* rv) {\n";
- if( item.m_markings.has_drop_impl )
+ if( has_drop_glue )
{
- m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
+ m_of << "fn " << drop_glue_path << "(&move " << ty << ") {\n";
+ if( item.m_markings.has_drop_impl ) {
+ m_of << "\tlet nms: &mut " << ty << ";\n";
+ }
+ m_of << "\t0: {\n";
+ if( item.m_markings.has_drop_impl )
+ {
+ m_of << "\t\t""ASSIGN nms = &mut *arg0;\n";
+ m_of << "\t\t""CALL unit = " << ::HIR::Path(ty.clone(), m_resolve.m_lang_Drop, "drop") << "(nms) goto 2 else 1\n";
+ m_of << "\t}\n";
+ m_of << "\t1: {\n";
+ m_of << "\t\tDIVERGE\n";
+ m_of << "\t}\n";
+ m_of << "\t2: {\n";
+ }
+ // NOTE: Unions don't drop inner values, but do call the destructor
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ m_of << "}\n";
}
- m_of << "}\n";
-#endif
}
void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override
@@ -542,11 +626,18 @@ namespace
TRACE_FUNCTION_F(p);
::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item);
+ // Generate the drop glue (and determine if there is any)
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ auto drop_glue_path = ::HIR::Path(ty.clone(), "drop_glue#");
+
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for enum " << ty);
m_of << "type " << p << " {\n";
m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n";
- // TODO: Drop glue path
+ if( has_drop_glue )
+ {
+ m_of << "\tDROP " << drop_glue_path << ";\n";
+ }
for(const auto& e : repr->fields)
{
m_of << "\t" << e.offset << " = " << e.ty << ";\n";
@@ -591,64 +682,61 @@ namespace
}
m_of << "}\n";
-#if 0
// ---
// - Drop Glue
// ---
- auto struct_ty = ::HIR::TypeRef(p.clone(), &item);
- auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue");
- auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone());
- auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath()));
- ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, empty_fcn };
- m_mir_res = &mir_res;
-
- if( item.m_markings.has_drop_impl )
- {
- m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(struct e_" << Trans_Mangle(p) << "*rv);\n";
- }
-
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n";
-
- // If this type has an impl of Drop, call that impl
- if( item.m_markings.has_drop_impl )
- {
- m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
- }
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
-
- if( nonzero_path.size() > 0 )
- {
- // TODO: Fat pointers?
- m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 );
- m_of << "\t}\n";
- }
- else if( const auto* e = item.m_data.opt_Data() )
+ if( has_drop_glue )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ m_of << "fn " << drop_glue_path << "(&move " << ty << ") {\n";
+ if( item.m_markings.has_drop_impl ) {
+ m_of << "\tlet nms: &mut " << ty << ";\n";
+ }
+ m_of << "\t0: {\n";
- m_of << "\tswitch(rv->TAG) {\n";
- for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ size_t first_drop_bb;
+ if( item.m_markings.has_drop_impl )
{
- var_lv.as_Downcast().variant_index = var_idx;
- m_of << "\tcase " << var_idx << ":\n";
- emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2);
- m_of << "\tbreak;\n";
+ m_of << "\t\t""ASSIGN nms = &mut *arg0;\n";
+ m_of << "\t\t""CALL unit = " << ::HIR::Path(ty.clone(), m_resolve.m_lang_Drop, "drop") << "(nms) goto 2 else 1\n";
+ m_of << "\t}\n";
+ m_of << "\t1: {\n";
+ m_of << "\t\tDIVERGE\n";
+ m_of << "\t}\n";
+ m_of << "\t2: {\n";
+ first_drop_bb = 3;
}
- m_of << "\t}\n";
- }
- else
- {
- // Value enum
- // Glue does nothing (except call the destructor, if there is one)
+ else
+ {
+ first_drop_bb = 1;
+ }
+ if( const auto* e = item.m_data.opt_Data() )
+ {
+ m_of << "\t\tSWITCH *arg0 { ";
+ for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ {
+ if( var_idx != 0 )
+ {
+ m_of << ", ";
+ }
+ m_of << (first_drop_bb + var_idx);
+ }
+ m_of << " }\n";
+ m_of << "\t}\n";
+ for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ {
+ m_of << "\t" << (first_drop_bb+var_idx) << ": {\n";
+ m_of << "\t\tDROP (*arg0)@" << var_idx << ";\n";
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ }
+ }
+ else
+ {
+ m_of << "\t}\n";
+ }
+ m_of << "}\n";
}
- m_of << "}\n";
- if( nonzero_path.size() )
- {
- m_enum_repr_cache.insert( ::std::make_pair( p.clone(), mv$(nonzero_path) ) );
- }
-#endif
m_mir_res = nullptr;
}
struct Reloc {
@@ -656,6 +744,13 @@ namespace
size_t len;
const ::HIR::Path* p;
::std::string bytes;
+
+ static Reloc new_named(size_t ofs, size_t len, const ::HIR::Path* p) {
+ return Reloc { ofs, len, p, "" };
+ }
+ static Reloc new_bytes(size_t ofs, size_t len, ::std::string bytes) {
+ return Reloc { ofs, len, nullptr, ::std::move(bytes) };
+ }
};
void emit_str_byte(uint8_t b) {
if( b == 0 ) {
@@ -845,9 +940,9 @@ namespace
{
ASSERT_BUG(sp, lit.is_String(), ty << " not Literal::String - " << lit);
const auto& s = lit.as_String();
- putsize(0);
+ putsize(PTR_BASE + 0);
putsize(s.size());
- out_relocations.push_back(Reloc { base_ofs, 8, nullptr, s });
+ out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s));
break;
}
// fall
@@ -856,35 +951,41 @@ namespace
size_t ity_size, ity_align;
Target_GetSizeAndAlignOf(sp, m_resolve, ity, ity_size, ity_align);
bool is_unsized = (ity_size == SIZE_MAX);
- if( lit.is_BorrowPath() )
- {
- putsize(0);
- out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" });
+
+ TU_MATCH_HDRA( (lit), { )
+ TU_ARMA(BorrowPath, le) {
+ putsize(PTR_BASE);
+ out_relocations.push_back(Reloc::new_named(base_ofs, 8, &le));
if( is_unsized )
{
// TODO: Get the size of the pointed-to array
// OR: Find out the source item type and the target trait.
putsize(0);
}
- break;
- }
- else if( lit.is_Integer() )
- {
- ASSERT_BUG(sp, lit.as_Integer() == 0, "Pointer from integer not 0");
+ }
+ TU_ARMA(Integer, le) {
+ ASSERT_BUG(sp, le == 0, "Pointer from integer not 0");
ASSERT_BUG(sp, ty.m_data.is_Pointer(), "Borrow from integer");
- putsize(0);
+ putsize(le);
if( is_unsized )
{
putsize(0);
}
- break;
+ }
+ TU_ARMA(String, le) {
+ const auto& s = lit.as_String();
+ putsize(PTR_BASE);
+ putsize(s.size());
+ out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s));
+ }
+ break; default:
+ TODO(sp, "Emit a pointer - " << ty << " from literal " << lit);
}
- TODO(sp, "Pointers - " << ty << " w/ " << lit);
} break;
case ::HIR::TypeRef::Data::TAG_Function:
ASSERT_BUG(sp, lit.is_BorrowPath(), ty << " not Literal::BorrowPath - " << lit);
- putsize(0);
- out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" });
+ putsize(PTR_BASE);
+ out_relocations.push_back(Reloc::new_named(base_ofs, 8, &lit.as_BorrowPath()));
break;
TU_ARM(ty.m_data, Array, te) {
// What about byte strings?
@@ -936,16 +1037,17 @@ namespace
const size_t ptr_size = Target_GetCurSpec().m_arch.m_pointer_bits / 8;
const auto& trait_path = p.m_data.as_UfcsKnown().trait;
const auto& type = *p.m_data.as_UfcsKnown().type;
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, type);
::HIR::TypeRef vtable_ty;
{
- auto vtable_sp = trait_path.m_path;
- vtable_sp.m_components.back() += "#vtable";
+ const auto& vtable_sp = trait.m_vtable_path;
auto vtable_params = trait_path.m_params.clone();
for(const auto& ty : trait.m_type_indexes) {
auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) );
m_resolve.expand_associated_types(sp, aty);
vtable_params.m_types.push_back( mv$(aty) );
+ //vtable_params.m_types.at(ty.second) = ::std::move(aty);
}
const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp);
vtable_ty = ::HIR::TypeRef( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref );
@@ -956,7 +1058,7 @@ namespace
m_of << "static " << p << ": " << vtable_ty << " = \"";
// - Data
// Drop
- emit_str_usize(0);
+ emit_str_usize(has_drop_glue ? PTR_BASE : 0);
// Align
emit_str_usize(align);
// Size
@@ -964,15 +1066,17 @@ namespace
// Methods
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
- emit_str_usize(0);
+ emit_str_usize(PTR_BASE);
}
m_of << "\" {";
// - Relocations
auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr);
// Drop
- // - TODO: Some types don't have drop glue
- m_of << "@0+" << ptr_size << " = " << ::HIR::Path(type.clone(), "drop_glue#") << ", ";
+ if( has_drop_glue )
+ {
+ m_of << "@0+" << ptr_size << " = " << ::HIR::Path(type.clone(), "drop_glue#") << ", ";
+ }
// Methods
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
@@ -1029,11 +1133,6 @@ namespace
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code };
m_mir_res = &mir_res;
- if( item.m_linkage.name != "" )
- {
- // TODO: Save the linkage name.
- }
-
// - Signature
m_of << "fn " << p << "(";
for(unsigned int i = 0; i < item.m_args.size(); i ++)
@@ -1041,7 +1140,12 @@ namespace
if( i != 0 ) m_of << ", ";
m_of << params.monomorph(m_resolve, item.m_args[i].second);
}
- m_of << "): " << ret_type << " {\n";
+ m_of << "): " << ret_type;
+ if( item.m_linkage.name != "" )
+ {
+ m_of << " = \"" << item.m_linkage.name << "\":\"" << item.m_abi << "\"";
+ }
+ m_of << " {\n";
// - Locals
for(unsigned int i = 0; i < code->locals.size(); i ++) {
DEBUG("var" << i << " : " << code->locals[i]);
@@ -1103,8 +1207,8 @@ namespace
case ::MIR::eBinOp::SUB_OV: m_of << "-^"; break;
case ::MIR::eBinOp::MUL: m_of << "*"; break;
case ::MIR::eBinOp::MUL_OV: m_of << "*^"; break;
- case ::MIR::eBinOp::DIV: m_of << "*"; break;
- case ::MIR::eBinOp::DIV_OV: m_of << "*^"; break;
+ case ::MIR::eBinOp::DIV: m_of << "/"; break;
+ case ::MIR::eBinOp::DIV_OV: m_of << "/^"; break;
case ::MIR::eBinOp::MOD: m_of << "%"; break;
case ::MIR::eBinOp::BIT_OR: m_of << "|"; break;
case ::MIR::eBinOp::BIT_AND:m_of << "&"; break;
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index 4e04ddf9..d8426022 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -11,6 +11,7 @@
#include "trans_list.hpp"
#include <hir/hir.hpp>
#include <mir/mir.hpp>
+#include <mir/helpers.hpp>
#include <hir_typeck/common.hpp> // monomorph
#include <hir_typeck/static.hpp> // StaticTraitResolve
#include <hir/item_path.hpp>
@@ -47,11 +48,12 @@ namespace {
TransList Trans_Enumerate_CommonPost(EnumState& state);
void Trans_Enumerate_Types(EnumState& state);
void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp);
+void Trans_Enumerate_FillFrom_PathMono(EnumState& state, ::HIR::Path path);
void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, const Trans_Params& pp);
void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& stat, TransList_Static& stat_out, Trans_Params pp={});
void Trans_Enumerate_FillFrom_VTable (EnumState& state, ::HIR::Path vtable_path, const Trans_Params& pp);
void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& lit, const Trans_Params& pp);
-void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp);
+void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code);
/// Enumerate trans items starting from `::main` (binary crate)
TransList Trans_Enumerate_Main(const ::HIR::Crate& crate)
@@ -63,21 +65,25 @@ TransList Trans_Enumerate_Main(const ::HIR::Crate& crate)
auto c_start_path = crate.get_lang_item_path_opt("mrustc-start");
if( c_start_path == ::HIR::SimplePath() )
{
+ // user entrypoint
+ auto main_path = crate.get_lang_item_path(Span(), "mrustc-main");
+ const auto& main_fcn = crate.get_function_by_path(sp, main_path);
+
+ state.enum_fcn( main_path, main_fcn, {} );
+
// "start" language item
// - Takes main, and argc/argv as arguments
{
auto start_path = crate.get_lang_item_path(sp, "start");
const auto& fcn = crate.get_function_by_path(sp, start_path);
- state.enum_fcn( start_path, fcn, {} );
- }
-
- // user entrypoint
- {
- auto main_path = crate.get_lang_item_path(Span(), "mrustc-main");
- const auto& fcn = crate.get_function_by_path(sp, main_path);
-
- state.enum_fcn( main_path, fcn, {} );
+ Trans_Params lang_start_pp;
+ if( TARGETVER_1_29 )
+ {
+ // With 1.29, this now takes main's return type as a type parameter
+ lang_start_pp.pp_method.m_types.push_back( main_fcn.m_return.clone() );
+ }
+ state.enum_fcn( start_path, fcn, mv$(lang_start_pp) );
}
}
else
@@ -148,39 +154,29 @@ namespace {
const bool EMIT_ALL = true;
for(auto& vi : mod.m_value_items)
{
- Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->is_public), [&](){ return mod_path + vi.first; });
+ Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->publicity.is_global()), [&](){ return mod_path + vi.first; });
}
for(auto& ti : mod.m_mod_items)
{
if(auto* e = ti.second->ent.opt_Module() )
{
- Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->is_public);
+ Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->publicity.is_global());
}
}
}
-}
-
-/// Enumerate trans items for all public non-generic items (library crate)
-TransList Trans_Enumerate_Public(::HIR::Crate& crate)
-{
- static Span sp;
- EnumState state { crate };
- Trans_Enumerate_Public_Mod(state, crate.m_root_module, ::HIR::SimplePath(crate.m_crate_name,{}), true);
-
- // Impl blocks
- StaticTraitResolve resolve { crate };
- for(auto& impl : crate.m_trait_impls)
+ void Trans_Enumerate_Public_TraitImpl(EnumState& state, StaticTraitResolve& resolve, const ::HIR::SimplePath& trait_path, /*const*/ ::HIR::TraitImpl& impl)
{
- const auto& impl_ty = impl.second.m_type;
- TRACE_FUNCTION_F("Impl " << impl.first << impl.second.m_trait_args << " for " << impl_ty);
- if( impl.second.m_params.m_types.size() == 0 )
+ static Span sp;
+ const auto& impl_ty = impl.m_type;
+ TRACE_FUNCTION_F("Impl " << trait_path << impl.m_trait_args << " for " << impl_ty);
+ if( impl.m_params.m_types.size() == 0 )
{
- auto cb_monomorph = monomorphise_type_get_cb(sp, &impl_ty, &impl.second.m_trait_args, nullptr);
+ auto cb_monomorph = monomorphise_type_get_cb(sp, &impl_ty, &impl.m_trait_args, nullptr);
// Emit each method/static (in the trait itself)
- const auto& trait = crate.get_trait_by_path(sp, impl.first);
+ const auto& trait = resolve.m_crate.get_trait_by_path(sp, trait_path);
for(const auto& vi : trait.m_values)
{
TRACE_FUNCTION_F("Item " << vi.first << " : " << vi.second.tag_str());
@@ -222,11 +218,12 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
if( !rv )
continue ;
}
- auto p = ::HIR::Path(impl_ty.clone(), ::HIR::GenericPath(impl.first, impl.second.m_trait_args.clone()), vi.first);
- Trans_Enumerate_FillFrom_Path(state, p, {});
+ auto path = ::HIR::Path(impl_ty.clone(), ::HIR::GenericPath(trait_path, impl.m_trait_args.clone()), vi.first);
+ Trans_Enumerate_FillFrom_PathMono(state, mv$(path));
+ //state.enum_fcn(mv$(path), fcn.second.data, {});
}
}
- for(auto& m : impl.second.m_methods)
+ for(auto& m : impl.m_methods)
{
if( m.second.data.m_params.m_types.size() > 0 )
m.second.data.m_save_code = true;
@@ -234,37 +231,88 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
}
else
{
- for(auto& m : impl.second.m_methods)
+ for(auto& m : impl.m_methods)
{
m.second.data.m_save_code = true;
}
}
}
- for(auto& impl : crate.m_type_impls)
+}
+
+/// Enumerate trans items for all public non-generic items (library crate)
+TransList Trans_Enumerate_Public(::HIR::Crate& crate)
+{
+ static Span sp;
+ EnumState state { crate };
+
+ Trans_Enumerate_Public_Mod(state, crate.m_root_module, ::HIR::SimplePath(crate.m_crate_name,{}), true);
+
+ // Impl blocks
+ StaticTraitResolve resolve { crate };
+ for(auto& impl_group : crate.m_trait_impls)
{
- if( impl.m_params.m_types.size() == 0 )
+ const auto& trait_path = impl_group.first;
+ for(auto& impl_list : impl_group.second.named)
{
- for(auto& fcn : impl.m_methods)
+ for(auto& impl : impl_list.second)
{
- if( fcn.second.data.m_params.m_types.size() == 0 )
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ }
+ for(auto& impl : impl_group.second.non_named)
+ {
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ for(auto& impl : impl_group.second.generic)
+ {
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ }
+ struct H1
+ {
+ static void enumerate_type_impl(EnumState& state, ::HIR::TypeImpl& impl)
+ {
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type);
+ if( impl.m_params.m_types.size() == 0 )
+ {
+ for(auto& fcn : impl.m_methods)
{
- auto p = ::HIR::Path(impl.m_type.clone(), fcn.first);
- Trans_Enumerate_FillFrom_Path(state, p, {});
+ DEBUG("fn " << fcn.first << fcn.second.data.m_params.fmt_args());
+ if( fcn.second.data.m_params.m_types.size() == 0 )
+ {
+ auto path = ::HIR::Path(impl.m_type.clone(), fcn.first);
+ state.enum_fcn(mv$(path), fcn.second.data, {});
+ }
+ else
+ {
+ fcn.second.data.m_save_code = true;
+ }
}
- else
+ }
+ else
+ {
+ for(auto& m : impl.m_methods)
{
- fcn.second.data.m_save_code = true;
+ m.second.data.m_save_code = true;
}
}
}
- else
+ };
+ for(auto& impl_grp : crate.m_type_impls.named)
+ {
+ for(auto& impl : impl_grp.second)
{
- for(auto& m : impl.m_methods)
- {
- m.second.data.m_save_code = true;
- }
+ H1::enumerate_type_impl(state, *impl);
}
}
+ for(auto& impl : crate.m_type_impls.non_named)
+ {
+ H1::enumerate_type_impl(state, *impl);
+ }
+ for(auto& impl : crate.m_type_impls.generic)
+ {
+ H1::enumerate_type_impl(state, *impl);
+ }
auto rv = Trans_Enumerate_CommonPost(state);
@@ -332,6 +380,7 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
return rv;
}
+#if 0
void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list)
{
EnumState state { crate };
@@ -377,6 +426,7 @@ void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list)
ASSERT_BUG(Span(), it != list.m_functions.end(), "Enumerate Error - New function appeared after monomorphisation - " << e.first);
}
}
+#endif
/// Common post-processing
void Trans_Enumerate_CommonPost_Run(EnumState& state)
@@ -400,7 +450,8 @@ TransList Trans_Enumerate_CommonPost(EnumState& state)
return mv$(state.rv);
}
-namespace {
+namespace
+{
struct PtrComp
{
template<typename T>
@@ -413,7 +464,8 @@ namespace {
::StaticTraitResolve m_resolve;
::std::vector< ::std::pair< ::HIR::TypeRef, bool> >& out_list;
- ::std::map< ::HIR::TypeRef, bool > visited;
+ // TODO: Have a list of indexes into `out_list`, sorted by typeref ordering
+ ::std::vector<size_t> visited_map;
::std::set< const ::HIR::TypeRef*, PtrComp> active_set;
TypeVisitor(const ::HIR::Crate& crate, ::std::vector< ::std::pair< ::HIR::TypeRef, bool > >& out_list):
@@ -422,6 +474,11 @@ namespace {
out_list(out_list)
{}
+ ~TypeVisitor()
+ {
+ DEBUG("Visited a total of " << visited_map.size());
+ }
+
void visit_struct(const ::HIR::GenericPath& path, const ::HIR::Struct& item) {
static Span sp;
::HIR::TypeRef tmp;
@@ -499,16 +556,16 @@ namespace {
{
// If the type has already been visited, AND either this is a shallow visit, or the previous wasn't
{
- auto it = visited.find(ty);
- if( it != visited.end() )
+ auto idx_it = ::std::lower_bound(visited_map.begin(), visited_map.end(), ty, [&](size_t i, const ::HIR::TypeRef& t){ return out_list[i].first < t; });
+ if( idx_it != visited_map.end() && out_list[*idx_it].first == ty)
{
+ auto it = &out_list[*idx_it];
if( it->second == false || mode == Mode::Shallow )
{
// Return early
return ;
}
DEBUG("-- " << ty << " already visited as shallow");
- it->second = false;
}
}
TRACE_FUNCTION_F(ty << " - " << (mode == Mode::Shallow ? "Shallow" : (mode == Mode::Normal ? "Normal" : "Deep")));
@@ -566,6 +623,9 @@ namespace {
(Opaque,
BUG(Span(), "Opaque type hit in enumeration - " << ty);
),
+ (ExternType,
+ // No innards to visit
+ ),
(Struct,
visit_struct(te.path.m_data.as_Generic(), *tpb);
),
@@ -583,8 +643,7 @@ namespace {
const auto& trait = *te.m_trait.m_trait_ptr;
ASSERT_BUG(Span(), ! te.m_trait.m_path.m_path.m_components.empty(), "TODO: Data trait is empty, what can be done?");
- auto vtable_ty_spath = te.m_trait.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
@@ -626,36 +685,30 @@ namespace {
bool shallow = (mode == Mode::Shallow);
{
- auto rv = visited.insert( ::std::make_pair(ty.clone(), shallow) );
- if( !rv.second && ! shallow )
+ auto idx_it = ::std::lower_bound(visited_map.begin(), visited_map.end(), ty, [&](size_t i, const ::HIR::TypeRef& t){ return out_list[i].first < t; });
+ if( idx_it == visited_map.end() || out_list[*idx_it].first != ty )
{
- rv.first->second = false;
+ // Add a new entry
+ visited_map.insert(idx_it, out_list.size());
+ }
+ else
+ {
+ // Previous visit was shallow, but this one isn't
+ // - Update the entry to the to-be-pushed entry with shallow=false
+ if( !shallow && out_list[*idx_it].second )
+ {
+ *idx_it = out_list.size();
+ }
}
}
out_list.push_back( ::std::make_pair(ty.clone(), shallow) );
DEBUG("Add type " << ty << (shallow ? " (Shallow)": ""));
}
- };
-}
-
-// Enumerate types required for the enumerated items
-void Trans_Enumerate_Types(EnumState& state)
-{
- static Span sp;
- TypeVisitor tv { state.crate, state.rv.m_types };
- unsigned int types_count = 0;
- bool constructors_added;
- do
- {
- // Visit all functions that haven't been type-visited yet
- for(unsigned int i = 0; i < state.fcns_to_type_visit.size(); i++)
+ void __attribute__ ((noinline)) visit_function(const ::HIR::Path& path, const ::HIR::Function& fcn, const Trans_Params& pp)
{
- auto p = state.fcns_to_type_visit[i];
- TRACE_FUNCTION_F("Function " << ::std::find_if(state.rv.m_functions.begin(), state.rv.m_functions.end(), [&](const auto&x){ return x.second.get() == p; })->first);
- assert(p->ptr);
- const auto& fcn = *p->ptr;
- const auto& pp = p->pp;
+ Span sp;
+ auto& tv = *this;
::HIR::TypeRef tmp;
auto monomorph = [&](const auto& ty)->const auto& {
@@ -693,284 +746,170 @@ void Trans_Enumerate_Types(EnumState& state)
for(const auto& ty : mir.locals)
tv.visit_type(monomorph(ty));
- // TODO: Find all LValue::Deref instances and get the result type
+ // Find all LValue::Deref instances and get the result type
+ ::MIR::TypeResolve::args_t empty_args;
+ ::HIR::TypeRef empty_ty;
+ ::MIR::TypeResolve mir_res(sp, tv.m_resolve, FMT_CB(fcn_path), /*ret_ty=*/empty_ty, empty_args, mir);
for(const auto& block : mir.blocks)
{
- struct H {
- static const ::HIR::TypeRef& visit_lvalue(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::LValue& lv, ::HIR::TypeRef* tmp_ty_ptr = nullptr) {
- static ::HIR::TypeRef blank;
- TRACE_FUNCTION_F(lv << (tmp_ty_ptr ? " [type]" : ""));
+ struct MirVisitor
+ //:public ::MIR::Visitor
+ {
+ TypeVisitor& tv;
+ const Trans_Params& pp;
+ const ::HIR::Function& fcn;
+ const ::MIR::TypeResolve& mir_res;
+
+ MirVisitor(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::TypeResolve& mir_res)
+ :tv(tv)
+ ,pp(pp)
+ ,fcn(fcn)
+ ,mir_res(mir_res)
+ {
+ }
+
+ void visit_lvalue(const ::MIR::LValue& lv) //override
+ {
+ TRACE_FUNCTION_F(lv);
+ if( ::std::none_of(lv.m_wrappers.begin(), lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
+ {
+ return ;
+ }
+ ::HIR::TypeRef tmp;
auto monomorph_outer = [&](const auto& tpl)->const auto& {
- assert(tmp_ty_ptr);
if( monomorphise_type_needed(tpl) ) {
- return *tmp_ty_ptr = pp.monomorph(tv.m_resolve, tpl);
+ return tmp = pp.monomorph(tv.m_resolve, tpl);
}
else {
return tpl;
}
};
+ const ::HIR::TypeRef* ty_p = nullptr;;
// Recurse, if Deref get the type and add it to the visitor
- TU_MATCHA( (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- if( tmp_ty_ptr ) {
- TODO(Span(), "Get return type for MIR type enumeration");
- }
+ MIR_TODO(mir_res, "Get return type for MIR type enumeration");
),
(Argument,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_args[e.idx].second);
- }
+ ty_p = &monomorph_outer(fcn.m_args[e].second);
),
(Local,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_code.m_mir->locals[e]);
- }
+ ty_p = &monomorph_outer(fcn.m_code.m_mir->locals[e]);
),
(Static,
- if( tmp_ty_ptr ) {
- const auto& path = e;
- TU_MATCHA( (path.m_data), (pe),
- (Generic,
- ASSERT_BUG(Span(), pe.m_params.m_types.empty(), "Path params on static - " << path);
- const auto& s = tv.m_resolve.m_crate.get_static_by_path(Span(), pe.m_path);
- return s.m_type;
- ),
- (UfcsKnown,
- TODO(Span(), "LValue::Static - UfcsKnown - " << path);
- ),
- (UfcsUnknown,
- BUG(Span(), "Encountered UfcsUnknown in LValue::Static - " << path);
- ),
- (UfcsInherent,
- TODO(Span(), "LValue::Static - UfcsInherent - " << path);
- )
- )
- }
- ),
- (Field,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Field access of unexpected type - " << ity);
- ),
- (Tuple,
- return te[e.field_index];
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- ),
- (Path,
- ASSERT_BUG(Span(), te.binding.is_Struct(), "Field on non-Struct - " << ity);
- const auto& str = *te.binding.as_Struct();
- auto monomorph = [&](const auto& ty)->const auto& {
- if( monomorphise_type_needed(ty) ) {
- *tmp_ty_ptr = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return ty;
- }
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(Span(), "Field on unit-like struct - " << ity);
- ),
- (Tuple,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).ent);
- ),
- (Named,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).second.ent);
- )
- )
- )
- )
- }
- ),
- (Deref,
- ::HIR::TypeRef tmp;
- if( !tmp_ty_ptr ) tmp_ty_ptr = &tmp;
-
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Deref of unexpected type - " << ity);
+ // TODO: Monomorphise the path then hand to MIR::TypeResolve?
+ const auto& path = e;
+ TU_MATCHA( (path.m_data), (pe),
+ (Generic,
+ MIR_ASSERT(mir_res, pe.m_params.m_types.empty(), "Path params on static - " << path);
+ const auto& s = tv.m_resolve.m_crate.get_static_by_path(mir_res.sp, pe.m_path);
+ ty_p = &s.m_type;
),
- (Path,
- if( const auto* inner_ptr = tv.m_resolve.is_type_owned_box(ity) )
- {
- DEBUG("- Add type " << ity);
- tv.visit_type(*inner_ptr);
- return *inner_ptr;
- }
- else {
- BUG(Span(), "Deref on unexpected type - " << ity);
- }
+ (UfcsKnown,
+ MIR_TODO(mir_res, "LValue::Static - UfcsKnown - " << path);
),
- (Borrow,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsUnknown,
+ MIR_BUG(mir_res, "Encountered UfcsUnknown in LValue::Static - " << path);
),
- (Pointer,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsInherent,
+ MIR_TODO(mir_res, "LValue::Static - UfcsInherent - " << path);
)
)
- ),
- (Index,
- visit_lvalue(tv,pp,fcn, *e.idx, tmp_ty_ptr);
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Index of unexpected type - " << ity);
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- )
- )
- }
- ),
- (Downcast,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Downcast on unexpected type - " << ity);
- ),
- (Path,
- if( te.binding.is_Enum() )
- {
- const auto& enm = *te.binding.as_Enum();
- auto monomorph = [&](const auto& ty)->auto {
- ::HIR::TypeRef rv = monomorphise_type(pp.sp, enm.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, rv);
- return rv;
- };
- ASSERT_BUG(Span(), enm.m_data.is_Data(), "");
- const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(Span(), e.variant_index < variants.size(), "Variant index out of range");
- const auto& raw_ty = variants[e.variant_index].type;
- if( monomorphise_type_needed(raw_ty) ) {
- return *tmp_ty_ptr = monomorph(raw_ty);
- }
- else {
- return raw_ty;
- }
- }
- else
- {
- const auto& unm = *te.binding.as_Union();
- ASSERT_BUG(Span(), e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
- const auto& var_ty = variant.second.ent;
-
- if( monomorphise_type_needed(var_ty) ) {
- *tmp_ty_ptr = monomorphise_type(pp.sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
- tv.m_resolve.expand_associated_types(pp.sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return var_ty;
- }
- }
- )
- )
- }
)
)
- return blank;
+ assert(ty_p);
+ for(const auto& w : lv.m_wrappers)
+ {
+ ty_p = &mir_res.get_unwrapped_type(tmp, w, *ty_p);
+ if( w.is_Deref() )
+ {
+ tv.visit_type(*ty_p);
+ }
+ }
}
- static void visit_param(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Param& p)
+ void visit_const(const ::MIR::Constant& p)
+ {
+ }
+
+ void visit_param(const ::MIR::Param& p)
{
TU_MATCHA( (p), (e),
(LValue,
- H::visit_lvalue(tv, pp, fcn, e);
+ this->visit_lvalue(e);
),
(Constant,
+ this->visit_const(e);
)
)
}
};
+ MirVisitor mir_visit(tv, pp, fcn, mir_res);
for(const auto& stmt : block.statements)
{
TU_MATCHA( (stmt), (se),
(Drop,
- H::visit_lvalue(tv,pp,fcn, se.slot);
+ mir_visit.visit_lvalue(se.slot);
),
(SetDropFlag,
),
(Asm,
for(const auto& v : se.outputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
for(const auto& v : se.inputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
),
(ScopeEnd,
),
(Assign,
- H::visit_lvalue(tv,pp,fcn, se.dst);
+ mir_visit.visit_lvalue(se.dst);
TU_MATCHA( (se.src), (re),
(Use,
- H::visit_lvalue(tv,pp,fcn, re);
+ mir_visit.visit_lvalue(re);
),
(Constant,
+ mir_visit.visit_const(re);
),
(SizedArray,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Borrow,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(Cast,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(BinOp,
- H::visit_param(tv,pp,fcn, re.val_l);
- H::visit_param(tv,pp,fcn, re.val_l);
+ mir_visit.visit_param(re.val_l);
+ mir_visit.visit_param(re.val_r);
),
(UniOp,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstMeta,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstPtr,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(MakeDst,
- H::visit_param(tv,pp,fcn, re.ptr_val);
- H::visit_param(tv,pp,fcn, re.meta_val);
+ mir_visit.visit_param(re.ptr_val);
+ mir_visit.visit_param(re.meta_val);
),
(Tuple,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Array,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Variant,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Struct,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
)
)
)
@@ -983,32 +922,65 @@ void Trans_Enumerate_Types(EnumState& state)
(Goto, ),
(Panic, ),
(If,
- H::visit_lvalue(tv,pp,fcn, te.cond);
+ mir_visit.visit_lvalue(te.cond);
),
(Switch,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(SwitchValue,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(Call,
- if( te.fcn.is_Value() )
- H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value());
- else if( te.fcn.is_Intrinsic() )
+ if(const auto* e = te.fcn.opt_Value() )
+ {
+ mir_visit.visit_lvalue(*e);
+ }
+ else if(const auto* e = te.fcn.opt_Intrinsic())
{
- for(const auto& ty : te.fcn.as_Intrinsic().params.m_types)
+ for(const auto& ty : e->params.m_types)
tv.visit_type(monomorph(ty));
}
- H::visit_lvalue(tv,pp,fcn, te.ret_val);
+ else
+ {
+ // Paths don't need visiting?
+ }
+ mir_visit.visit_lvalue(te.ret_val);
for(const auto& arg : te.args)
- H::visit_param(tv,pp,fcn, arg);
+ mir_visit.visit_param(arg);
)
)
}
}
}
+ }; // struct TypeVisitor
+} // namespace <empty>
+
+// Enumerate types required for the enumerated items
+void Trans_Enumerate_Types(EnumState& state)
+{
+ static Span sp;
+ TypeVisitor tv { state.crate, state.rv.m_types };
+
+ unsigned int types_count = 0;
+ bool constructors_added;
+ do
+ {
+ // Visit all functions that haven't been type-visited yet
+ for(unsigned int i = 0; i < state.fcns_to_type_visit.size(); i++)
+ {
+ auto* p = state.fcns_to_type_visit[i];
+ assert(p->path);
+ assert(p->ptr);
+ auto& fcn_path = *p->path;
+ const auto& fcn = *p->ptr;
+ const auto& pp = p->pp;
+
+ TRACE_FUNCTION_F("Function " << fcn_path);
+ tv.visit_function(fcn_path, fcn, pp);
+ }
state.fcns_to_type_visit.clear();
// TODO: Similarly restrict revisiting of statics.
+ // - Challenging, as they're stored as a std::map
for(const auto& ent : state.rv.m_statics)
{
TRACE_FUNCTION_F("Enumerate static " << ent.first);
@@ -1024,8 +996,7 @@ void Trans_Enumerate_Types(EnumState& state)
const auto& gpath = ent.first.m_data.as_UfcsKnown().trait;
const auto& trait = state.crate.get_trait_by_path(sp, gpath.m_path);
- auto vtable_ty_spath = gpath.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = state.crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = gpath.m_params.clone();
@@ -1056,27 +1027,16 @@ void Trans_Enumerate_Types(EnumState& state)
if( ty.m_data.is_Path() )
{
const auto& te = ty.m_data.as_Path();
- const ::HIR::TraitMarkings* markings_ptr = nullptr;
- TU_MATCHA( (te.binding), (tpb),
- (Unbound, ),
- (Opaque, ),
- (Struct,
- markings_ptr = &tpb->m_markings;
- ),
- (Union,
- markings_ptr = &tpb->m_markings;
- ),
- (Enum,
- markings_ptr = &tpb->m_markings;
- )
- )
- ASSERT_BUG(Span(), markings_ptr, "Path binding not set correctly - " << ty);
+ ASSERT_BUG(sp, te.path.m_data.is_Generic(), "Non-Generic type path after enumeration - " << ty);
+ const auto& gp = te.path.m_data.as_Generic();
+ const ::HIR::TraitMarkings* markings_ptr = te.binding.get_trait_markings();
+ ASSERT_BUG(sp, markings_ptr, "Path binding not set correctly - " << ty);
// If the type has a drop impl, and it's either defined in this crate or has params (and thus was monomorphised)
- if( markings_ptr->has_drop_impl && (te.path.m_data.as_Generic().m_path.m_crate_name == state.crate.m_crate_name || te.path.m_data.as_Generic().m_params.has_params()) )
+ if( markings_ptr->has_drop_impl && (gp.m_path.m_crate_name == state.crate.m_crate_name || gp.m_params.has_params()) )
{
// Add the Drop impl to the codegen list
- Trans_Enumerate_FillFrom_Path(state, ::HIR::Path( ty.clone(), state.crate.get_lang_item_path(sp, "drop"), "drop"), {});
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path( ty.clone(), state.crate.get_lang_item_path(sp, "drop"), "drop"));
constructors_added = true;
}
}
@@ -1086,7 +1046,7 @@ void Trans_Enumerate_Types(EnumState& state)
// Reqire drop glue for inner type.
// - Should that already exist?
// Requires box_free lang item
- Trans_Enumerate_FillFrom_Path(state, ::HIR::GenericPath( state.crate.get_lang_item_path(sp, "box_free"), { ity->clone() } ), {});;
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::GenericPath( state.crate.get_lang_item_path(sp, "box_free"), { ity->clone() } ));
}
}
types_count = state.rv.m_types.size();
@@ -1180,14 +1140,14 @@ namespace {
return true;
}
}
- //{
- // auto it = impl.m_constants.find(e.item);
- // if( it != impl.m_constants.end() )
- // {
- // rv = EntPtr { &it->second.data };
- // return true;
- // }
- //}
+ {
+ auto it = impl.m_constants.find(pe->item);
+ if( it != impl.m_constants.end() )
+ {
+ rv = EntPtr { &it->second.data };
+ return true;
+ }
+ }
return false;
});
return rv;
@@ -1203,23 +1163,24 @@ namespace {
const auto& trait_vi = trait_vi_it->second;
bool is_dynamic = false;
+ bool any_impl = false;
::std::vector<::HIR::TypeRef> best_impl_params;
const ::HIR::TraitImpl* best_impl = nullptr;
resolve.find_impl(sp, pe->trait.m_path, pe->trait.m_params, *pe->type, [&](auto impl_ref, auto is_fuzz) {
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;
}
+ any_impl = true;
const auto& impl_ref_e = impl_ref.m_data.as_TraitImpl();
const auto& impl = *impl_ref_e.impl;
ASSERT_BUG(sp, impl.m_trait_args.m_types.size() == pe->trait.m_params.m_types.size(), "Trait parameter count mismatch " << impl.m_trait_args << " vs " << pe->trait.m_params);
if( best_impl == nullptr || impl.more_specific_than(*best_impl) ) {
- best_impl = &impl;
bool is_spec = false;
TU_MATCHA( (trait_vi), (ve),
(Constant,
@@ -1233,7 +1194,8 @@ namespace {
(Static,
if( pe->item == "vtable#" ) {
is_spec = true;
- break;
+ DEBUG("VTable, quick return");
+ return true;
}
auto it = impl.m_statics.find(pe->item);
if( it == impl.m_statics.end() ) {
@@ -1251,6 +1213,7 @@ namespace {
is_spec = fit->second.is_specialisable;
)
)
+ best_impl = &impl;
best_impl_params.clear();
for(unsigned int i = 0; i < impl_ref_e.params.size(); i ++)
{
@@ -1269,50 +1232,62 @@ namespace {
});
if( is_dynamic )
return EntPtr::make_AutoGenerate( {} );
- if( !best_impl )
+ if( !any_impl )
return EntPtr {};
- const auto& impl = *best_impl;
+ if( best_impl )
+ {
+ const auto& impl = *best_impl;
- impl_pp.m_types = mv$(best_impl_params);
+ impl_pp.m_types = mv$(best_impl_params);
- TU_MATCHA( (trait_vi), (ve),
- (Constant,
- auto it = impl.m_constants.find(pe->item);
- if( it != impl.m_constants.end() )
- {
+ // Fallback on default/provided items
+ TU_MATCH_HDRA( (trait_vi), {)
+ TU_ARMA(Constant, ve) {
+ auto it = impl.m_constants.find(pe->item);
+ ASSERT_BUG(sp, it != impl.m_constants.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &it->second.data };
- }
- TODO(sp, "Associated constant - " << path);
- ),
- (Static,
- if( pe->item == "vtable#" )
- {
- DEBUG("VTable, autogen");
- return EntPtr::make_AutoGenerate( {} );
- }
- auto it = impl.m_statics.find(pe->item);
- if( it != impl.m_statics.end() )
- {
+ }
+ TU_ARMA(Static, ve) {
+ assert(pe->item != "vtable#");
+ auto it = impl.m_statics.find(pe->item);
+ ASSERT_BUG(sp, it != impl.m_statics.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &it->second.data };
- }
- TODO(sp, "Associated static - " << path);
- ),
- (Function,
- auto fit = impl.m_methods.find(pe->item);
- if( fit != impl.m_methods.end() )
- {
+ }
+ TU_ARMA(Function, ve) {
+ auto fit = impl.m_methods.find(pe->item);
+ ASSERT_BUG(sp, fit != impl.m_methods.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &fit->second.data };
+ }
}
- impl_pp = pe->trait.m_params.clone();
- // HACK! By adding a new parameter here, the MIR will always be monomorphised
- impl_pp.m_types.push_back( ::HIR::TypeRef() );
- return EntPtr { &ve };
- )
- )
- BUG(sp, "");
+ }
+ else
+ {
+ // Fallback on default/provided items
+ TU_MATCH_HDRA( (trait_vi), {)
+ TU_ARMA(Constant, ve) {
+ TODO(sp, "Associated constant - " << path);
+ }
+ TU_ARMA(Static, ve) {
+ if( pe->item == "vtable#" )
+ {
+ DEBUG("VTable, autogen");
+ return EntPtr::make_AutoGenerate( {} );
+ }
+ TODO(sp, "Associated static - " << path);
+ }
+ TU_ARMA(Function, ve) {
+ ASSERT_BUG(sp, ve.m_code.m_mir, "Attempting to use default method with no body MIR - " << path);
+ impl_pp = pe->trait.m_params.clone();
+ // HACK! By adding a new parameter here, the MIR will always be monomorphised
+ impl_pp.m_types.push_back( ::HIR::TypeRef() );
+ return EntPtr { &ve };
+ }
+ }
+ }
+ throw "unreachable";
}
else
{
@@ -1323,12 +1298,75 @@ namespace {
}
}
+namespace MIR {
+ struct EnumCache
+ {
+ ::std::vector<const ::HIR::Path*> paths;
+ ::std::vector<const ::HIR::TypeRef*> typeids;
+ EnumCache()
+ {
+ }
+ void insert_path(const ::HIR::Path& new_path)
+ {
+ for(const auto* p : this->paths)
+ if( *p == new_path )
+ return ;
+ this->paths.push_back(&new_path);
+ }
+ void insert_typeid(const ::HIR::TypeRef& new_ty)
+ {
+ for(const auto* p : this->typeids)
+ if( *p == new_ty )
+ return ;
+ this->typeids.push_back(&new_ty);
+ }
+
+ void apply(EnumState& state, const Trans_Params& pp) const
+ {
+ for(const auto* ty_p : this->typeids)
+ {
+ state.rv.m_typeids.insert( pp.monomorph(state.crate, *ty_p) );
+ }
+ for(const auto& path : this->paths)
+ {
+ Trans_Enumerate_FillFrom_Path(state, *path, pp);
+ }
+ }
+ };
+ EnumCachePtr::~EnumCachePtr()
+ {
+ delete this->p;
+ this->p = nullptr;
+ }
+}
+
void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp)
{
- TRACE_FUNCTION_F(path);
- Span sp;
auto path_mono = pp.monomorph(state.crate, path);
- DEBUG("- " << path_mono);
+ Trans_Enumerate_FillFrom_PathMono(state, mv$(path_mono));
+}
+void Trans_Enumerate_FillFrom_PathMono(EnumState& state, ::HIR::Path path_mono)
+{
+ TRACE_FUNCTION_F(path_mono);
+ Span sp;
+ // TODO: If already in the list, return early
+ if( state.rv.m_functions.count(path_mono) ) {
+ DEBUG("> Already done function");
+ return ;
+ }
+ if( state.rv.m_statics.count(path_mono) ) {
+ DEBUG("> Already done static");
+ return ;
+ }
+ if( state.rv.m_constants.count(path_mono) ) {
+ DEBUG("> Already done constant");
+ return ;
+ }
+ if( state.rv.m_vtables.count(path_mono) ) {
+ DEBUG("> Already done vtable");
+ return ;
+ }
+
Trans_Params sub_pp(sp);
TU_MATCHA( (path_mono.m_data), (pe),
(Generic,
@@ -1344,17 +1382,17 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
sub_pp.self_type = pe.type->clone();
),
(UfcsUnknown,
- BUG(sp, "UfcsUnknown - " << path);
+ BUG(sp, "UfcsUnknown - " << path_mono);
)
)
// Get the item type
// - Valid types are Function and Static
auto item_ref = get_ent_fullpath(sp, state.crate, path_mono, sub_pp.pp_impl);
- TU_MATCHA( (item_ref), (e),
- (NotFound,
+ TU_MATCH_HDRA( (item_ref), {)
+ TU_ARMA(NotFound, e) {
BUG(sp, "Item not found for " << path_mono);
- ),
- (AutoGenerate,
+ }
+ TU_ARMA(AutoGenerate, e) {
if( path_mono.m_data.is_Generic() )
{
// Leave generation of struct/enum constructors to codgen
@@ -1376,58 +1414,102 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
// Must have been a dynamic dispatch request, just leave as-is
}
// - <fn(...) as Fn*>::call*
- else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() )
+ else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() && (
+ path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn")
+ || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_mut")
+ || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_once")
+ ) )
{
// 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" || pe.item == "clone_from", "Unexpected Clone method called, " << path_mono);
+ const auto& inner_ty = *pe.type;
+ // If this is !Copy, then we need to ensure that the inner type's clone impls are also available
+ ::StaticTraitResolve resolve { state.crate };
+ if( !resolve.type_is_copy(sp, inner_ty) )
+ {
+ auto enum_impl = [&](const ::HIR::TypeRef& ity) {
+ if( !resolve.type_is_copy(sp, ity) )
+ {
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path(ity.clone(), pe.trait.clone(), pe.item));
+ }
+ };
+ if( const auto* te = inner_ty.m_data.opt_Tuple() ) {
+ for(const auto& ity : *te)
+ {
+ enum_impl(ity);
+ }
+ }
+ else if( const auto* te = inner_ty.m_data.opt_Array() ) {
+ enum_impl(*te->inner);
+ }
+ else if( TU_TEST2(inner_ty.m_data, Path, .path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
+ const auto& gp = inner_ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& str = state.crate.get_struct_by_path(sp, gp.m_path);
+ Trans_Params p;
+ p.sp = sp;
+ p.pp_impl = gp.m_params.clone();
+ for(const auto& fld : str.m_data.as_Tuple())
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(resolve, fld.ent)) : fld.ent;
+ enum_impl(ty_m);
+ }
+ }
+ else {
+ BUG(sp, "Unhandled magic clone in enumerate - " << inner_ty);
+ }
+ }
+ // Add this type to a list of types that will have the impl auto-generated
+ state.rv.auto_clone_impls.insert( inner_ty.clone() );
+ }
else
{
BUG(sp, "AutoGenerate returned for unknown path type - " << path_mono);
}
- ),
- (Function,
+ }
+ TU_ARMA(Function, e) {
// Add this path (monomorphised) to the queue
state.enum_fcn(mv$(path_mono), *e, mv$(sub_pp));
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
if( auto* ptr = state.rv.add_static(mv$(path_mono)) )
{
Trans_Enumerate_FillFrom(state, *e, *ptr, mv$(sub_pp));
}
- ),
- (Constant,
- Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp);
- )
- )
+ }
+ TU_ARMA(Constant, e) {
+ if( e->m_value_res.is_Defer() )
+ {
+ if( auto* slot = state.rv.add_const(mv$(path_mono)) )
+ {
+ MIR::EnumCache es;
+ Trans_Enumerate_FillFrom_MIR(es, *e->m_value.m_mir);
+ es.apply(state, sub_pp);
+ slot->ptr = e;
+ slot->pp = ::std::move(sub_pp);
+ }
+ }
+ else
+ {
+ Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp);
+ }
+ }
+ }
}
-void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp)
+
+void Trans_Enumerate_FillFrom_MIR_LValue(MIR::EnumCache& state, const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- Trans_Enumerate_FillFrom_Path(state, e, pp);
- ),
- (Field,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- ),
- (Deref,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- ),
- (Index,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx, pp);
- ),
- (Downcast,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- )
- )
+ if( lv.m_root.is_Static() )
+ {
+ state.insert_path(lv.m_root.as_Static());
+ }
}
-void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Constant& c, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR_Constant(MIR::EnumCache& state, const ::MIR::Constant& c)
{
TU_MATCHA( (c), (ce),
(Int, ),
@@ -1437,21 +1519,22 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta
(Bytes, ),
(StaticString, ), // String
(Const,
- //Trans_Enumerate_FillFrom_Path(state, ce.p, pp);
+ // - Check if this constant has a value of Defer
+ state.insert_path(*ce.p);
),
(ItemAddr,
- Trans_Enumerate_FillFrom_Path(state, ce, pp);
+ state.insert_path(*ce);
)
)
}
-void Trans_Enumerate_FillFrom_MIR_Param(EnumState& state, const ::MIR::Param& p, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR_Param(MIR::EnumCache& state, const ::MIR::Param& p)
{
TU_MATCHA( (p), (e),
- (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); ),
- (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); )
+ (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e); ),
+ (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e); )
)
}
-void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code)
{
for(const auto& bb : code.blocks)
{
@@ -1460,63 +1543,63 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
TU_MATCHA((stmt), (se),
(Assign,
DEBUG("- " << se.dst << " = " << se.src);
- Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst);
TU_MATCHA( (se.src), (e),
(Use,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e);
),
(Constant,
- Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp);
+ Trans_Enumerate_FillFrom_MIR_Constant(state, e);
),
(SizedArray,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val);
),
(Borrow,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(Cast,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(BinOp,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l, pp);
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r);
),
(UniOp,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(DstMeta,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(DstPtr,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(MakeDst,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val, pp);
- Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val);
),
(Tuple,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
),
(Array,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
),
(Variant,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val);
),
(Struct,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
)
)
),
(Asm,
DEBUG("- asm! ...");
for(const auto& v : se.inputs)
- Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, v.second);
for(const auto& v : se.outputs)
- Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, v.second);
),
(SetDropFlag,
),
@@ -1524,7 +1607,7 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
),
(Drop,
DEBUG("- DROP " << se.slot);
- Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot);
// TODO: Ensure that the drop glue for this type is generated
)
)
@@ -1537,32 +1620,32 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
(Goto, ),
(Panic, ),
(If,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond);
),
(Switch,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(SwitchValue,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(Call,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val);
TU_MATCHA( (e.fcn), (e2),
(Value,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e2, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e2);
),
(Path,
- Trans_Enumerate_FillFrom_Path(state, e2, pp);
+ state.insert_path(e2);
),
(Intrinsic,
if( e2.name == "type_id" ) {
// Add <T>::#type_id to the enumerate list
- state.rv.m_typeids.insert( pp.monomorph(state.crate, e2.params.m_types.at(0)) );
+ state.insert_typeid(e2.params.m_types.at(0));
}
)
)
for(const auto& arg : e.args)
- Trans_Enumerate_FillFrom_MIR_Param(state, arg, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, arg);
)
)
}
@@ -1582,7 +1665,7 @@ void Trans_Enumerate_FillFrom_VTable(EnumState& state, ::HIR::Path vtable_path,
{
DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first);
auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false);
- Trans_Enumerate_FillFrom_Path(state, ::HIR::Path(type.clone(), mv$(gpath), m.first), {});
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path(type.clone(), mv$(gpath), m.first));
}
}
@@ -1591,6 +1674,9 @@ void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& li
TU_MATCHA( (lit), (e),
(Invalid,
),
+ (Defer,
+ // TODO: Bug?
+ ),
(List,
for(const auto& v : e)
Trans_Enumerate_FillFrom_Literal(state, v, pp);
@@ -1621,7 +1707,7 @@ namespace {
TU_IFLET( ::HIR::ValueItem, vi.second->ent, Function, i,
if( i.m_code.m_mir && i.m_linkage.name != "" && i.m_linkage.name == name )
{
- out_path = (mod_path + vi.first.c_str()).get_simple_path();
+ out_path = (mod_path + vi.first).get_simple_path();
return &i;
}
)
@@ -1630,7 +1716,7 @@ namespace {
for(const auto& ti : mod.m_mod_items)
{
TU_IFLET( ::HIR::TypeItem, ti.second->ent, Module, i,
- if( auto rv = find_function_by_link_name(i, mod_path + ti.first.c_str(), name, out_path) )
+ if( auto rv = find_function_by_link_name(i, mod_path + ti.first, name, out_path) )
return rv;
)
}
@@ -1658,7 +1744,15 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function,
TRACE_FUNCTION_F("Function pp=" << pp.pp_method<<"+"<<pp.pp_impl);
if( function.m_code.m_mir )
{
- Trans_Enumerate_FillFrom_MIR(state, *function.m_code.m_mir, pp);
+ const auto& mir_fcn = *function.m_code.m_mir;
+ if( !mir_fcn.trans_enum_state )
+ {
+ auto* esp = new MIR::EnumCache();
+ Trans_Enumerate_FillFrom_MIR(*esp, *function.m_code.m_mir);
+ mir_fcn.trans_enum_state = ::MIR::EnumCachePtr(esp);
+ }
+ // TODO: Ensure that all types have drop glue generated too? (Iirc this is unconditional currently)
+ mir_fcn.trans_enum_state->apply(state, pp);
}
else
{
@@ -1692,4 +1786,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..af33ef35 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);
+extern void Trans_Codegen(const ::std::string& outfile, CodegenOutput out_ty, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, const ::std::string& hir_file);
diff --git a/src/trans/mangling.cpp b/src/trans/mangling.cpp
index 741d13dd..0b5d61d6 100644
--- a/src/trans/mangling.cpp
+++ b/src/trans/mangling.cpp
@@ -2,7 +2,7 @@
* MRustC - Rust Compiler
* - By John Hodge (Mutabah/thePowersGang)
*
- * trans/mangling.hpp
+ * trans/mangling.cpp
* - Name mangling support
*
*
@@ -22,18 +22,27 @@
#include <hir/path.hpp>
namespace {
- ::std::string escape_str(const ::std::string& s) {
+ ::std::string escape_str(const char* s, size_t len) {
::std::string output;
- output.reserve(s.size() + 1);
- for(auto v : s)
+ output.reserve(len + 1);
+ for(auto vp = s; vp != s + len; vp ++)
+ {
+ auto v= *vp;
if( v == '#' )
output += "$H";
else if( v == '-' )
output += "_";
else
output += v;
+ }
return output;
}
+ ::std::string escape_str(const RcString& s) {
+ return escape_str(s.c_str(), s.size());
+ }
+ ::std::string escape_str(const ::std::string& s) {
+ return escape_str(s.c_str(), s.size());
+ }
::FmtLambda emit_params(const ::HIR::PathParams& params)
{
return FMT_CB(ss,
diff --git a/src/trans/mangling_v2.cpp b/src/trans/mangling_v2.cpp
new file mode 100644
index 00000000..f907a6e3
--- /dev/null
+++ b/src/trans/mangling_v2.cpp
@@ -0,0 +1,292 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * trans/mangling_v2.cpp
+ * - Name mangling (encoding of rust paths into symbols)
+ */
+#include <debug.hpp>
+#include <string_view.hpp>
+#include <hir/hir.hpp> // ABI_RUST
+#include <hir/type.hpp>
+
+class Mangler
+{
+ ::std::ostream& m_os;
+public:
+ Mangler(::std::ostream& os):
+ m_os(os)
+ {
+ }
+
+ // Item names:
+ // - These can have a single '#' in them (either leading or in the middle)
+ // TODO: Some other invalid characters can appear:
+ // - '-' (crate names)
+ void fmt_name(const RcString& s)
+ {
+ this->fmt_name(s.c_str());
+ }
+ void fmt_name(const char* const s)
+ {
+ size_t size = strlen(s);
+ const char* hash_pos = nullptr;
+ // - Search the string for the '#' character
+ for(const auto* p = s; *p; p++)
+ {
+ if( p == s ) {
+ ASSERT_BUG(Span(), !isdigit(*p), "Leading digit not valid in '" << s << "'");
+ }
+
+ if( isalnum(*p) ) {
+ }
+ else if( *p == '_' ) {
+ }
+ else if( *p == '#' || *p == '-' ) { // HACK: Treat '-' and '#' as the same in encoding
+ // Multiple hash characters? abort/error
+ ASSERT_BUG(Span(), hash_pos == nullptr, "Multiple '#' characters in '" << s << "'");
+ hash_pos = p;
+ }
+ else {
+ BUG(Span(), "Encounteded invalid character '" << *p << "' in '" << s << "'");
+ }
+ }
+
+ // If there's a hash, then prefix with a letter indicating its location?
+ // - Using a 3 character overhead currently (but a letter could work really well)
+ if( hash_pos != nullptr )
+ {
+ auto pre_hash_len = static_cast<int>(hash_pos - s);
+#if 0
+ assert(pre_hash_len < 26);
+ // <posletter> <full_len> <body1> <body2>
+ m_os << 'a' + pre_hash_len;
+ m_os << size - 1;
+ m_os << ::stdx::string_view(s, s + pre_hash_len);
+ m_os << hash_pos + 1;;
+#else
+ // 'h' <len1> <body1> <len2> <body2>
+ m_os << "h";
+ m_os << pre_hash_len;
+ m_os << ::stdx::string_view(s, s + pre_hash_len);
+ m_os << size - pre_hash_len - 1;
+ m_os << hash_pos + 1;;
+#endif
+ }
+ else
+ {
+ m_os << size;
+ m_os << s;
+ }
+ }
+ // SimplePath : <ncomp> 'c' [<RcString> ...]
+ void fmt_simple_path(const ::HIR::SimplePath& sp)
+ {
+ m_os << sp.m_components.size();
+ m_os << "c"; // Needed to separate the component count from the crate name
+ this->fmt_name(sp.m_crate_name);
+ for(const auto& c : sp.m_components)
+ {
+ this->fmt_name(c);
+ }
+ }
+
+ // PathParams : <ntys> 'g' [<TypeRef> ...]
+ void fmt_path_params(const ::HIR::PathParams& pp)
+ {
+ // Type Parameter count
+ m_os << pp.m_types.size();
+ m_os << "g";
+ for(const auto& ty : pp.m_types)
+ {
+ fmt_type(ty);
+ }
+ }
+ // GenericPath : <SimplePath> <PathParams>
+ void fmt_generic_path(const ::HIR::GenericPath& gp)
+ {
+ this->fmt_simple_path(gp.m_path);
+ this->fmt_path_params(gp.m_params);
+ }
+
+ void fmt_path(const ::HIR::Path& p)
+ {
+ // Path type
+ // - Generic: starts with `G`
+ // - Inherent: Starts with `I`
+ // - Trait: Starts with `Q` (qualified)
+ // - bare type: Starts with `T` (see Trans_MangleType)
+ TU_MATCH_HDRA( (p.m_data), {)
+ TU_ARMA(Generic, e) {
+ m_os << "G";
+ this->fmt_generic_path(e);
+ }
+ TU_ARMA(UfcsInherent, e) {
+ m_os << "I";
+ this->fmt_type(*e.type);
+ this->fmt_name(e.item);
+ this->fmt_path_params(e.params);
+ }
+ TU_ARMA(UfcsKnown, e) {
+ m_os << "Q";
+ this->fmt_type(*e.type);
+ this->fmt_generic_path(e.trait);
+ this->fmt_name(e.item);
+ this->fmt_path_params(e.params);
+ }
+ TU_ARMA(UfcsUnknown, e)
+ BUG(Span(), "Non-encodable path " << p);
+ }
+ }
+
+ // Type
+ // - Tuple: 'T' <nelem> [<TypeRef> ...]
+ // - Slice: 'S' <TypeRef>
+ // - Array: 'A' <size> <TypeRef>
+ // - Path: 'N' <Path>
+ // - TraitObject: 'D' <data:GenericPath> <nmarker> [markers: <GenericPath> ...] <naty> [<TypeRef> ...] TODO: Does this need to include the ATY name?
+ // - Borrow: 'B' ('s'|'u'|'o') <TypeRef>
+ // - RawPointer: 'P' ('s'|'u'|'o') <TypeRef>
+ // - Function: 'F' <abi:RcString> <nargs> [args: <TypeRef> ...] <ret:TypeRef>
+ // - Primitives::
+ // - u8 : 'C' 'a'
+ // - i8 : 'C' 'b'
+ // - u16 : 'C' 'c'
+ // - i16 : 'C' 'd'
+ // - u32 : 'C' 'e'
+ // - i32 : 'C' 'f'
+ // - u64 : 'C' 'g'
+ // - i64 : 'C' 'h'
+ // - u128: 'C' 'i'
+ // - i128: 'C' 'j'
+ // --
+ // - f32 : 'C' 'n'
+ // - f64 : 'C' 'o'
+ // --
+ // - usize: 'C' 'u'
+ // - isize: 'C' 'v'
+ // - bool : 'C' 'x'
+ // - char : 'C' 'x'
+ // - str : 'C' 'y'
+ // - Diverge: 'C' 'z'
+ void fmt_type(const ::HIR::TypeRef& ty)
+ {
+ TU_MATCH_HDRA( (ty.m_data), { )
+ case ::HIR::TypeRef::Data::TAG_Infer:
+ case ::HIR::TypeRef::Data::TAG_Generic:
+ case ::HIR::TypeRef::Data::TAG_ErasedType:
+ case ::HIR::TypeRef::Data::TAG_Closure:
+ BUG(Span(), "Non-encodable type " << ty);
+ TU_ARMA(Tuple, e) {
+ m_os << "T" << e.size();
+ for(const auto& sty : e)
+ this->fmt_type(sty);
+ }
+ TU_ARMA(Slice, e) {
+ m_os << "S";
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Array, e) {
+ m_os << "A" << e.size_val;
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Path, e) {
+ m_os << "N";
+ this->fmt_path(e.path);
+ }
+ TU_ARMA(TraitObject, e) {
+ // - TraitObject: 'D' <data:GenericPath> <naty> [<TypeRef> ...] <nmarker> [markers: <GenericPath> ...]
+ m_os << "D";
+ this->fmt_generic_path(e.m_trait.m_path);
+ m_os << e.m_trait.m_type_bounds.size();
+ // HACK: Assume all TraitObject types have the same aty set (std::map is deterministic)
+ for(const auto& aty : e.m_trait.m_type_bounds)
+ this->fmt_type(aty.second);
+ m_os << e.m_markers.size();
+ for(const auto& p : e.m_markers)
+ this->fmt_generic_path(p);
+ }
+ TU_ARMA(Function, e) {
+ // - Function: 'F' <abi:RcString> <nargs> [args: <TypeRef> ...] <ret:TypeRef>
+ m_os << "F";
+ m_os << (e.is_unsafe ? "u" : ""); // Optional allowed, next is a number
+ if( e.m_abi != ABI_RUST )
+ {
+ m_os << "e";
+ this->fmt_name(e.m_abi.c_str());
+ }
+ m_os << e.m_arg_types.size();
+ for(const auto& t : e.m_arg_types)
+ this->fmt_type(t);
+ this->fmt_type(*e.m_rettype);
+ }
+ TU_ARMA(Borrow, e) {
+ m_os << "B";
+ switch(e.type)
+ {
+ case ::HIR::BorrowType::Shared: m_os << "s"; break;
+ case ::HIR::BorrowType::Unique: m_os << "u"; break;
+ case ::HIR::BorrowType::Owned: m_os << "o"; break;
+ }
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Pointer, e) {
+ m_os << "P";
+ switch(e.type)
+ {
+ case ::HIR::BorrowType::Shared: m_os << "s"; break;
+ case ::HIR::BorrowType::Unique: m_os << "u"; break;
+ case ::HIR::BorrowType::Owned: m_os << "o"; break;
+ }
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Primitive, e) {
+ switch(e)
+ {
+ case ::HIR::CoreType::U8 : m_os << 'C' << 'a'; break;
+ case ::HIR::CoreType::I8 : m_os << 'C' << 'b'; break;
+ case ::HIR::CoreType::U16 : m_os << 'C' << 'c'; break;
+ case ::HIR::CoreType::I16 : m_os << 'C' << 'd'; break;
+ case ::HIR::CoreType::U32 : m_os << 'C' << 'e'; break;
+ case ::HIR::CoreType::I32 : m_os << 'C' << 'f'; break;
+ case ::HIR::CoreType::U64 : m_os << 'C' << 'g'; break;
+ case ::HIR::CoreType::I64 : m_os << 'C' << 'h'; break;
+ case ::HIR::CoreType::U128: m_os << 'C' << 'i'; break;
+ case ::HIR::CoreType::I128: m_os << 'C' << 'j'; break;
+ case ::HIR::CoreType::F32 : m_os << 'C' << 'n'; break;
+ case ::HIR::CoreType::F64 : m_os << 'C' << 'o'; break;
+ case ::HIR::CoreType::Usize: m_os << 'C' << 'u'; break;
+ case ::HIR::CoreType::Isize: m_os << 'C' << 'v'; break;
+ case ::HIR::CoreType::Bool: m_os << 'C' << 'w'; break;
+ case ::HIR::CoreType::Char: m_os << 'C' << 'x'; break;
+ case ::HIR::CoreType::Str : m_os << 'C' << 'y'; break;
+ }
+ }
+ TU_ARMA(Diverge, _e) {
+ m_os << 'C' << 'z';
+ }
+ }
+ }
+};
+
+::FmtLambda Trans_ManglePath(const ::HIR::Path& p)
+{
+ return FMT_CB(os, os << "ZR"; Mangler(os).fmt_path(p));
+}
+::FmtLambda Trans_MangleSimplePath(const ::HIR::SimplePath& p)
+{
+ return FMT_CB(os, os << "ZRG"; Mangler(os).fmt_simple_path(p); Mangler(os).fmt_path_params({}););
+}
+::FmtLambda Trans_MangleGenericPath(const ::HIR::GenericPath& p)
+{
+ return FMT_CB(os, os << "ZRG"; Mangler(os).fmt_generic_path(p));
+}
+::FmtLambda Trans_MangleType(const ::HIR::TypeRef& p)
+{
+ return FMT_CB(os, os << "ZRT"; Mangler(os).fmt_type(p));
+}
+
+::FmtLambda Trans_Mangle(const ::HIR::SimplePath& path) { return Trans_MangleSimplePath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::GenericPath& path) { return Trans_MangleGenericPath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::Path& path) { return Trans_ManglePath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::TypeRef& ty) { return Trans_MangleType(ty); }
diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp
index 892cb730..b5099918 100644
--- a/src/trans/monomorphise.cpp
+++ b/src/trans/monomorphise.cpp
@@ -10,42 +10,19 @@
#include <mir/mir.hpp>
#include <hir/hir.hpp>
#include <mir/operations.hpp> // Needed for post-monomorph checks and optimisations
+#include <hir_conv/constant_evaluation.hpp>
namespace {
::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl)
{
- TU_MATCHA( (tpl), (e),
- (Return, return e; ),
- (Argument, return e; ),
- (Local, return e; ),
- (Static,
- return params.monomorph(resolve, e);
- ),
- (Field,
- return ::MIR::LValue::make_Field({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.field_index
- });
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({
- box$(monomorph_LValue(resolve, params, *e.val))
- });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(monomorph_LValue(resolve, params, *e.val)),
- box$(monomorph_LValue(resolve, params, *e.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.variant_index
- });
- )
- )
- throw "";
+ if( tpl.m_root.is_Static() )
+ {
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(params.monomorph(resolve, tpl.m_root.as_Static())), tpl.m_wrappers );
+ }
+ else
+ {
+ return tpl.clone();
+ }
}
::MIR::Constant monomorph_Constant(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::Constant& tpl)
{
@@ -70,15 +47,15 @@ namespace {
),
(Const,
return ::MIR::Constant::make_Const({
- params.monomorph(resolve, ce.p)
+ box$(params.monomorph(resolve, *ce.p))
});
),
(ItemAddr,
- auto p = params.monomorph(resolve, ce);
+ auto p = params.monomorph(resolve, *ce);
// TODO: If this is a pointer to a function on a trait object, replace with the address loaded from the vtable.
// - Requires creating a new temporary for the vtable pointer.
// - Also requires knowing what the receiver is.
- return ::MIR::Constant( mv$(p) );
+ return ::MIR::Constant( box$(p) );
)
)
throw "";
@@ -117,6 +94,7 @@ namespace {
{
static Span sp;
TRACE_FUNCTION;
+ assert(tpl);
::MIR::Function output;
@@ -350,6 +328,7 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
const auto& path = fcn_ent.first;
const auto& pp = fcn_ent.second->pp;
TRACE_FUNCTION_FR(path, path);
+ ASSERT_BUG(Span(), fcn.m_code.m_mir, "No code for " << path);
auto mir = Trans_Monomorphise(resolve, fcn_ent.second->pp, fcn.m_code.m_mir);
@@ -359,8 +338,8 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
for(const auto& a : fcn.m_args)
args.push_back(::std::make_pair( ::HIR::Pattern{}, pp.monomorph(resolve, a.second) ));
- ::std::string s = FMT(path);
- ::HIR::ItemPath ip(s);
+ //::std::string s = FMT(path);
+ ::HIR::ItemPath ip(path);
MIR_Validate(resolve, ip, *mir, args, ret_type);
MIR_Cleanup(resolve, ip, *mir, args, ret_type);
MIR_Optimise(resolve, ip, *mir, args, ret_type);
@@ -371,5 +350,32 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
fcn_ent.second->monomorphised.code = ::std::move(mir);
}
}
+
+ // Also do constants and statics (stored in where?)
+ // - NOTE: Done in reverse order, because consteval needs used constants to be evaluated
+ for(auto& ent : reverse(list.m_constants))
+ {
+ const auto& path = ent.first;
+ const auto& pp = ent.second->pp;
+ const auto& c = *ent.second->ptr;
+ TRACE_FUNCTION_FR(path, path);
+ auto ty = pp.monomorph(resolve, c.m_type);
+ // 1. Evaluate the constant
+ struct Nvs: public ::HIR::Evaluator::Newval
+ {
+ ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override {
+ TODO(Span(), "Create new static in monomorph pass - " << value << " : " << type);
+ }
+ } nvs;
+ auto eval = ::HIR::Evaluator { pp.sp, crate, nvs };
+ MonomorphState ms;
+ ms.self_ty = &pp.self_type;
+ ms.pp_impl = &pp.pp_impl;
+ ms.pp_method = &pp.pp_method;
+ auto new_lit = eval.evaluate_constant(path, c.m_value, ::std::move(ty), ::std::move(ms));
+ ASSERT_BUG(Span(), !new_lit.is_Defer(), "Result of evaluating " << path << " was still Defer");
+ // 2. Store evaluated HIR::Literal in c.m_monomorph_cache
+ c.m_monomorph_cache.insert(::std::make_pair( path.clone(), ::std::move(new_lit) ));
+ }
}
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index 70996fb0..de5492a8 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -404,21 +404,21 @@ namespace
ARCH_M68K
};
}
- else if(target_name == "i586-windows-gnu")
+ else if(target_name == "i586-pc-windows-gnu")
{
return TargetSpec {
"windows", "windows", "gnu", {CodegenMode::Gnu11, true, "mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
- else if(target_name == "x86_64-windows-gnu")
+ else if(target_name == "x86_64-pc-windows-gnu")
{
return TargetSpec {
"windows", "windows", "gnu", {CodegenMode::Gnu11, false, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
- else if (target_name == "x86-windows-msvc")
+ else if (target_name == "x86-pc-windows-msvc")
{
// TODO: Should this include the "kernel32.lib" inclusion?
return TargetSpec {
@@ -426,7 +426,7 @@ namespace
ARCH_X86
};
}
- else if (target_name == "x86_64-windows-msvc")
+ else if (target_name == "x86_64-pc-windows-msvc")
{
return TargetSpec {
"windows", "windows", "msvc", {CodegenMode::Msvc, true, "amd64", {}, {}},
@@ -595,6 +595,7 @@ void Target_SetCfg(const ::std::string& target_name)
if(s == "32") return g_target.m_arch.m_atomics.u32;
if(s == "64") return g_target.m_arch.m_atomics.u64;
if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value
+ if(s == "cas") return g_target.m_arch.m_atomics.ptr; // TODO: Atomic compare-and-set option
return false;
});
Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
@@ -602,139 +603,6 @@ void Target_SetCfg(const ::std::string& target_name)
});
}
-namespace {
- // Returns NULL when the repr can't be determined
- ::std::unique_ptr<StructRepr> make_struct_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
- {
- TRACE_FUNCTION_F(ty);
- ::std::vector<StructRepr::Ent> ents;
- bool packed = false;
- bool allow_sort = false;
- if( const auto* te = ty.m_data.opt_Path() )
- {
- const auto& str = *te->binding.as_Struct();
- auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te->path.m_data.as_Generic().m_params, nullptr);
- auto monomorph = [&](const auto& tpl) {
- auto rv = monomorphise_type_with(sp, tpl, monomorph_cb);
- resolve.expand_associated_types(sp, rv);
- return rv;
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- ),
- (Tuple,
- unsigned int idx = 0;
- for(const auto& e : se)
- {
- auto ty = monomorph(e.ent);
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in tuple struct");
- ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
- }
- ),
- (Named,
- unsigned int idx = 0;
- for(const auto& e : se)
- {
- auto ty = monomorph(e.second.ent);
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in struct");
- ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
- }
- )
- )
- switch(str.m_repr)
- {
- case ::HIR::Struct::Repr::Packed:
- packed = true;
- TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen to know to pack the structure
- break;
- case ::HIR::Struct::Repr::Simd:
- case ::HIR::Struct::Repr::C:
- // No sorting, no packing
- break;
- case ::HIR::Struct::Repr::Rust:
- allow_sort = true;
- break;
- }
- }
- else if( const auto* te = ty.m_data.opt_Tuple() )
- {
- unsigned int idx = 0;
- for(const auto& t : *te)
- {
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in tuple");
- ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() });
- }
- }
- else
- {
- BUG(sp, "Unexpected type in creating struct repr");
- }
-
-
- if( allow_sort )
- {
- // TODO: Sort by alignment then size (largest first)
- // - Requires codegen to use this information
- }
-
- StructRepr rv;
- size_t cur_ofs = 0;
- size_t max_align = 1;
- for(auto& e : ents)
- {
- // Increase offset to fit alignment
- if( !packed )
- {
- while( cur_ofs % e.align != 0 )
- {
- rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) });
- cur_ofs ++;
- }
- }
- max_align = ::std::max(max_align, e.align);
-
- rv.ents.push_back(mv$(e));
- cur_ofs += e.size;
- }
- if( !packed )
- {
- while( cur_ofs % max_align != 0 )
- {
- rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) });
- cur_ofs ++;
- }
- }
- return box$(rv);
- }
-}
-const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
-{
- // TODO: Thread safety
- // Map of generic paths to struct representations.
- static ::std::map<::HIR::TypeRef, ::std::unique_ptr<StructRepr>> s_cache;
-
- auto it = s_cache.find(ty);
- if( it != s_cache.end() )
- {
- return it->second.get();
- }
-
- auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_struct_repr(sp, resolve, ty) ));
- return ires.first->second.get();
-}
-
bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align)
{
TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align);
@@ -802,6 +670,15 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
}
),
(Path,
+ if( te.binding.is_Opaque() )
+ return false;
+ if( te.binding.is_ExternType() )
+ {
+ DEBUG("sizeof on extern type - unsized");
+ out_align = 0;
+ out_size = SIZE_MAX;
+ return true;
+ }
const auto* repr = Target_GetTypeRepr(sp, resolve, ty);
if( !repr )
{
@@ -865,26 +742,39 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
// - Alignment is machine native
out_align = g_target.m_arch.m_pointer_bits / 8;
// - Size depends on Sized-nes of the parameter
- if( resolve.type_is_sized(sp, *te.inner) )
+ // TODO: Handle different types of Unsized (ones with different pointer sizes)
+ switch(resolve.metadata_type(sp, *te.inner))
{
+ case MetadataType::Unknown:
+ return false;
+ case MetadataType::None:
+ case MetadataType::Zero:
out_size = g_target.m_arch.m_pointer_bits / 8;
- return true;
+ break;
+ case MetadataType::Slice:
+ case MetadataType::TraitObject:
+ out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
+ break;
}
- // TODO: Handle different types of Unsized (ones with different pointer sizes)
- out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
return true;
),
(Pointer,
// - Alignment is machine native
out_align = g_target.m_arch.m_pointer_bits / 8;
// - Size depends on Sized-nes of the parameter
- if( resolve.type_is_sized(sp, *te.inner) )
+ switch(resolve.metadata_type(sp, *te.inner))
{
+ case MetadataType::Unknown:
+ return false;
+ case MetadataType::None:
+ case MetadataType::Zero:
out_size = g_target.m_arch.m_pointer_bits / 8;
- return true;
+ break;
+ case MetadataType::Slice:
+ case MetadataType::TraitObject:
+ out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
+ break;
}
- // TODO: Handle different types of Unsized (ones with different pointer sizes)
- out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
return true;
),
(Function,
@@ -911,7 +801,7 @@ bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const
{
size_t ignore_size;
bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align);
- if( ignore_size == SIZE_MAX )
+ if( rv && ignore_size == SIZE_MAX )
BUG(sp, "Getting alignment of Unsized type - " << ty);
return rv;
}
@@ -986,6 +876,9 @@ namespace {
case ::HIR::Struct::Repr::Simd:
// No sorting, no packing
break;
+ case ::HIR::Struct::Repr::Aligned:
+ // TODO: Update the minimum alignment
+ case ::HIR::Struct::Repr::Transparent:
case ::HIR::Struct::Repr::Rust:
allow_sort = true;
break;
@@ -1058,7 +951,7 @@ namespace {
cur_ofs ++;
}
}
- rv.align = max_align;
+ rv.align = packed ? 1 : max_align;
rv.size = cur_ofs;
rv.fields = ::std::move(fields);
DEBUG("size = " << rv.size << ", align = " << rv.align);
@@ -1368,6 +1261,11 @@ namespace {
{
return make_type_repr_enum(sp, resolve, ty);
}
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_ExternType()) )
+ {
+ // TODO: Do extern types need anything?
+ return nullptr;
+ }
else if( ty.m_data.is_Primitive() )
{
return nullptr;
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index 4e0309dd..3433483b 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -78,18 +78,6 @@ struct TargetSpec
TargetArch m_arch;
};
-struct StructRepr
-{
- struct Ent {
- unsigned int field_idx;
- size_t size;
- size_t align;
- ::HIR::TypeRef ty;
- };
- // List of types, including padding (indicated by a UINT_MAX field idx)
- // Ordered as they would be emitted
- ::std::vector<Ent> ents;
-};
struct TypeRepr
{
size_t align = 0;
@@ -137,7 +125,6 @@ extern void Target_ExportCurSpec(const ::std::string& filename);
extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size);
extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align);
extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align);
-extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& struct_ty);
extern const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty);
diff --git a/src/trans/trans_list.cpp b/src/trans/trans_list.cpp
index 04e1e9a1..3d8aa86f 100644
--- a/src/trans/trans_list.cpp
+++ b/src/trans/trans_list.cpp
@@ -15,7 +15,7 @@ TransList_Function* TransList::add_function(::HIR::Path p)
{
DEBUG("Function " << rv.first->first);
assert( !rv.first->second );
- rv.first->second.reset( new TransList_Function {} );
+ rv.first->second.reset( new TransList_Function(rv.first->first) );
return &*rv.first->second;
}
else
@@ -38,6 +38,21 @@ TransList_Static* TransList::add_static(::HIR::Path p)
return nullptr;
}
}
+TransList_Const* TransList::add_const(::HIR::Path p)
+{
+ auto rv = m_constants.insert( ::std::make_pair(mv$(p), nullptr) );
+ if( rv.second )
+ {
+ DEBUG("Const " << rv.first->first);
+ assert( !rv.first->second );
+ rv.first->second.reset( new TransList_Const {} );
+ return &*rv.first->second;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
t_cb_generic Trans_Params::get_cb() const
{
diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp
index 48274f87..7009111f 100644
--- a/src/trans/trans_list.hpp
+++ b/src/trans/trans_list.hpp
@@ -18,6 +18,7 @@ class Function;
class Static;
}
+// TODO: This is very similar to "hir_typeck/common.hpp" MonomorphState
struct Trans_Params
{
Span sp;
@@ -48,16 +49,27 @@ struct CachedFunction {
};
struct TransList_Function
{
+ const ::HIR::Path* path; // Pointer into the list (std::map pointers are stable)
const ::HIR::Function* ptr;
Trans_Params pp;
// If `pp.has_types` is true, the below is valid
CachedFunction monomorphised;
+
+ TransList_Function(const ::HIR::Path& path):
+ path(&path),
+ ptr(nullptr)
+ {}
};
struct TransList_Static
{
const ::HIR::Static* ptr;
Trans_Params pp;
};
+struct TransList_Const
+{
+ const ::HIR::Constant* ptr;
+ Trans_Params pp;
+};
class TransList
{
@@ -70,17 +82,22 @@ public:
::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Function> > m_functions;
::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Static> > m_statics;
+ /// Constants that are still Defer
+ ::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Const> > m_constants;
::std::map< ::HIR::Path, Trans_Params> m_vtables;
/// Required type_id values
::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;
TransList_Function* add_function(::HIR::Path p);
TransList_Static* add_static(::HIR::Path p);
+ TransList_Const* add_const(::HIR::Path p);
bool add_vtable(::HIR::Path p, Trans_Params pp) {
return m_vtables.insert( ::std::make_pair( mv$(p), mv$(pp) ) ).second;
}
diff --git a/src/version.cpp b/src/version.cpp
index af5ff552..9f62d5a5 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -14,10 +14,10 @@
#ifdef _WIN32
# define VERSION_GIT_ISDIRTY 1
-# define VERSION_GIT_FULLHASH ""
-# define VERSION_GIT_SHORTHASH ""
-# define VERSION_BUILDTIME ""
-# define VERSION_GIT_BRANCH ""
+# define VERSION_GIT_FULLHASH "unknown"
+# define VERSION_GIT_SHORTHASH "msvc"
+# define VERSION_BUILDTIME "unknown"
+# define VERSION_GIT_BRANCH "unknown"
#endif
unsigned int giVersion_Major = VERSION_MAJOR;