summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-10-01 21:42:19 +0800
committerJohn Hodge <tpg@mutabah.net>2016-10-01 21:42:19 +0800
commit5967b5ac48e1fcb50ce673fc96691392e2ae2692 (patch)
tree940029692aaad862eb8e92d0a79e43fdbee35042
parentd0bb03758d31dcba938e95bd2ee155bb798a9b70 (diff)
downloadmrust-5967b5ac48e1fcb50ce673fc96691392e2ae2692.tar.gz
HIR - Store and use annotations for CoerceUnsized (and prepare markings for other traits)
-rw-r--r--src/hir/from_ast.cpp1
-rw-r--r--src/hir/hir.cpp10
-rw-r--r--src/hir/hir.hpp22
-rw-r--r--src/hir_conv/bind.cpp50
-rw-r--r--src/hir_typeck/expr_cs.cpp52
-rw-r--r--src/hir_typeck/impl_ref.hpp9
-rw-r--r--src/main.cpp1
7 files changed, 134 insertions, 11 deletions
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index d80c1ed1..74697784 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -1313,6 +1313,7 @@ public:
}
auto sp = Span();
+ // - Store the lang item paths so conversion code can use them.
for( const auto& lang_item_path : crate.m_lang_items )
{
rv.m_lang_items.insert( ::std::make_pair(lang_item_path.first, LowerHIR_SimplePath(sp, lang_item_path.second)) );
diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp
index 40ad9f86..293827d8 100644
--- a/src/hir/hir.cpp
+++ b/src/hir/hir.cpp
@@ -397,13 +397,21 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const
const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path(const Span& sp, const char* name) const
{
- // TODO: have map stored in crate populated by (or from) the #[lang] attribute handler
auto it = this->m_lang_items.find( name );
if( it == this->m_lang_items.end() ) {
ERROR(sp, E0000, "Undefined language item '" << name << "' required");
}
return it->second;
}
+const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path_opt(const char* name) const
+{
+ static ::HIR::SimplePath empty_path;
+ auto it = this->m_lang_items.find( name );
+ if( it == this->m_lang_items.end() ) {
+ return empty_path;
+ }
+ return it->second;
+}
const ::HIR::TypeItem& ::HIR::Crate::get_typeitem_by_path(const Span& sp, const ::HIR::SimplePath& path, bool ignore_crate_name) const
{
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index c439960a..73e1fd95 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -128,6 +128,23 @@ struct TypeAlias
typedef ::std::vector< VisEnt<::HIR::TypeRef> > t_tuple_fields;
typedef ::std::vector< ::std::pair< ::std::string, VisEnt<::HIR::TypeRef> > > t_struct_fields;
+/// Cache of the state of various language traits on an enum/struct
+struct TraitMarkings
+{
+ /// There is at least one CoerceUnsized impl for this type
+ bool can_coerce = false;
+
+ /// Indicates that there is at least one Deref impl
+ bool has_a_deref = false;
+
+ /// Type is always unsized (i.e. contains an unsized type)
+ bool is_always_unsized = false;
+ /// Type is always sized (i.e. cannot contain any unsized types)
+ bool is_always_sized = false;
+ /// `true` if there is a Copy impl
+ bool is_copy = false;
+};
+
class Enum
{
public:
@@ -150,6 +167,8 @@ public:
GenericParams m_params;
Repr m_repr;
::std::vector< ::std::pair< ::std::string, Variant > > m_variants;
+
+ TraitMarkings m_markings;
};
class Struct
{
@@ -170,6 +189,8 @@ public:
GenericParams m_params;
Repr m_repr;
Data m_data;
+
+ TraitMarkings m_markings;
};
struct AssociatedType
@@ -332,6 +353,7 @@ public:
void post_load_update(const ::std::string& 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;
const ::HIR::TypeItem& get_typeitem_by_path(const Span& sp, const ::HIR::SimplePath& path, bool ignore_crate_name=false) const;
const ::HIR::Trait& get_trait_by_path(const Span& sp, const ::HIR::SimplePath& path) const;
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index 18e97a72..576941ca 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -1,5 +1,9 @@
/*
- * Set binding pointers in TypeRef and Pattern
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_conv/bind.cpp
+ * - Set binding pointers in HIR structures
*/
#include "main_bindings.hpp"
#include <hir/visitor.hpp>
@@ -8,6 +12,8 @@
#include <hir_typeck/static.hpp>
+void ConvertHIR_Bind(::HIR::Crate& crate);
+
namespace {
@@ -122,10 +128,14 @@ namespace {
public ::HIR::Visitor
{
const ::HIR::Crate& m_crate;
+ const ::HIR::SimplePath& m_lang_CoerceUnsized;
+ const ::HIR::SimplePath& m_lang_Deref;
public:
Visitor(const ::HIR::Crate& crate):
- m_crate(crate)
+ m_crate(crate),
+ m_lang_CoerceUnsized(m_crate.get_lang_item_path_opt("coerce_unsized")),
+ m_lang_Deref(m_crate.get_lang_item_path_opt("coerce_unsized"))
{}
void visit_trait_path(::HIR::TraitPath& p) override
@@ -448,6 +458,41 @@ namespace {
(*expr).visit(v);
}
}
+
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override
+ {
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+
+ TU_IFLET(::HIR::TypeRef::Data, impl.m_type.m_data, Path, te,
+ ::HIR::TraitMarkings* markings = nullptr;
+ TU_MATCHA( (te.binding), (tpb),
+ (Unbound,
+ // Wut?
+ ),
+ (Opaque,
+ // Just ignore, it's a wildcard... wait? is that valid?
+ ),
+ (Struct,
+ markings = &const_cast<HIR::Struct*>(tpb)->m_markings;
+ ),
+ (Enum,
+ markings = &const_cast<HIR::Enum*>(tpb)->m_markings;
+ )
+ )
+
+ if( markings )
+ {
+ // CoerceUnsized - set flag to avoid needless searches later
+ if( trait_path == m_lang_CoerceUnsized ) {
+ markings->can_coerce = true;
+ }
+ // Deref - set flag to avoid needless searches later
+ else if( trait_path == m_lang_Deref ) {
+ markings->has_a_deref = true;
+ }
+ }
+ )
+ }
};
}
@@ -456,6 +501,7 @@ 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 );
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 8ecbfeb8..8d76e21f 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -3769,14 +3769,38 @@ namespace {
return true;
}
+ const auto& lang_CoerceUnsized = context.m_crate.get_lang_item_path(sp, "coerce_unsized");
+
+ struct H {
+ // Check if a path type has or could have a CoerceUnsized impl
+ static bool type_has_coerce_path(const ::HIR::TypeRef& ty) {
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
+ TU_MATCHA( (e.binding), (pbe),
+ (Unbound,
+ ),
+ (Opaque,
+ // Assume true (could store something in the generic block)
+ return true;
+ ),
+ (Struct,
+ return pbe->m_markings.can_coerce;
+ ),
+ (Enum,
+ return pbe->m_markings.can_coerce;
+ )
+ )
+ )
+ return false;
+ }
+ };
+
// CoerceUnsized trait
// - Only valid for generic or path destination types
- if( ty_dst.m_data.is_Generic() || ty_dst.m_data.is_Path() )
+ if( ty_dst.m_data.is_Generic() || H::type_has_coerce_path(ty_dst) )
{
- const auto& lang_CoerceUnsized = context.m_crate.get_lang_item_path(sp, "coerce_unsized");
+ // `CoerceUnsized<U> for T` means `T -> U`
- ::HIR::PathParams pp;
- pp.m_types.push_back( ty_dst.clone() );
+ ::HIR::PathParams pp { ty_dst.clone() };
// PROBLEM: This can false-negative leading to the types being falsely equated.
@@ -3800,7 +3824,7 @@ namespace {
// - Concretely found - emit the _Unsize op and remove this rule
if( found )
{
- DEBUG("- CoerceUnsize " << &*node_ptr << " -> " << ty_dst);
+ DEBUG("- NEWNODE _Unsize " << &*node_ptr << " -> " << ty_dst);
auto span = node_ptr->span();
node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() );
@@ -3811,7 +3835,7 @@ namespace {
DEBUG("- best_impl = " << best_impl);
// Fuzzy match - Insert a CoerceUnsized bound and emit the _Unsize op
// - This could end up being a no-op _Unsize, and there's special logic in check_associated to handle `T: CoerceUnsized<T>` and `T: Unsize<T>`
- context.add_trait_bound(sp, ty_src, lang_CoerceUnsized, ::HIR::PathParams(ty_dst.clone()));
+ context.add_trait_bound(sp, ty_src, lang_CoerceUnsized, mv$(pp));
node_ptr = NEWNODE( ty_dst.clone(), sp, _Unsize, mv$(node_ptr), ty_dst.clone() );
return true;
}
@@ -3845,7 +3869,12 @@ namespace {
return true;
),
(Path,
- if( ! e.binding.is_Unbound() ) {
+ // If there is an impl of CoerceUnsized<_> for this, don't equate (just return and wait for a while)
+ if( H::type_has_coerce_path(ty_src) ) {
+ // TODO: Is unconditionally returning here a good thing?
+ //return false;
+ }
+ else {
// TODO: Use the CoerceUnsized trait here
context.equate_types(sp, ty_dst, node_ptr->m_res_type);
return true;
@@ -4144,6 +4173,7 @@ namespace {
// HACK! If the trait is `Unsize` then pretend `impl<T> Unsize<T> for T` exists to possibly propagate the type through
// - Also applies to CoerceUnsized (which may not get its impl detected because actually `T: !Unsize<T>`)
// - This is needed because `check_coerce` will emit coercions where they're not actually needed in some cases.
+ // `Unsize<U> for T` means `T -> U`
if( v.trait == context.m_crate.get_lang_item_path(sp, "unsize") )
{
ASSERT_BUG(sp, v.params.m_types.size() == 1, "Incorrect number of parameters for Unsize");
@@ -4188,6 +4218,7 @@ namespace {
}
if( v.trait == context.m_crate.get_lang_item_path(sp, "coerce_unsized") )
{
+ // `CoerceUnsized<U> for T` means when T is found an U is expected, a coerce can happen
ASSERT_BUG(sp, v.params.m_types.size() == 1, "Incorrect number of parameters for Unsize");
const auto& src_ty = context.get_type(v.impl_ty);
const auto& dst_ty = context.get_type(v.params.m_types[0]);
@@ -4196,7 +4227,7 @@ namespace {
// If the trait is CoerceUnsized and no impl could be found, equate.
bool found = context.m_resolve.find_trait_impls(sp, v.trait, v.params, v.impl_ty, [&](auto, auto) { return true; });
if( !found ) {
- DEBUG("No impl of CoerceUnsized, assume the types must be equal");
+ DEBUG("No impl of CoerceUnsized"<<v.params<<" for " << v.impl_ty << ", assume the types must be equal");
context.equate_types(sp, dst_ty, src_ty);
return true;
}
@@ -4271,6 +4302,11 @@ namespace {
else if( count == 1 ) {
DEBUG("Only one impl " << v.trait << context.m_ivars.fmt(possible_params) << " for " << context.m_ivars.fmt_type(possible_impl_ty)
<< " - params=" << possible_params << ", ty=" << possible_impl_ty << ", out=" << output_type);
+ // TODO: If there are any magic params in the impl, don't use it yet.
+ if( best_impl.has_magic_params() ) {
+ return false;
+ }
+
// Only one possible impl
if( v.name != "" ) {
context.equate_types(sp, v.left_ty, output_type);
diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp
index 910f445f..3135b4cc 100644
--- a/src/hir_typeck/impl_ref.hpp
+++ b/src/hir_typeck/impl_ref.hpp
@@ -51,6 +51,15 @@ struct ImplRef
bool more_specific_than(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() )
+ return true;
+ )
+ return false;
+ }
+
/// 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/main.cpp b/src/main.cpp
index cfa39976..c97b4946 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -249,6 +249,7 @@ int main(int argc, char *argv[])
CompilePhaseV("Resolve Type Aliases", [&]() {
ConvertHIR_ExpandAliases(*hir_crate);
});
+ // Set up bindings and other useful information.
CompilePhaseV("Resolve Bind", [&]() {
ConvertHIR_Bind(*hir_crate);
});