diff options
author | John Hodge <tpg@mutabah.net> | 2016-10-01 21:42:19 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-10-01 21:42:19 +0800 |
commit | 5967b5ac48e1fcb50ce673fc96691392e2ae2692 (patch) | |
tree | 940029692aaad862eb8e92d0a79e43fdbee35042 | |
parent | d0bb03758d31dcba938e95bd2ee155bb798a9b70 (diff) | |
download | mrust-5967b5ac48e1fcb50ce673fc96691392e2ae2692.tar.gz |
HIR - Store and use annotations for CoerceUnsized (and prepare markings for other traits)
-rw-r--r-- | src/hir/from_ast.cpp | 1 | ||||
-rw-r--r-- | src/hir/hir.cpp | 10 | ||||
-rw-r--r-- | src/hir/hir.hpp | 22 | ||||
-rw-r--r-- | src/hir_conv/bind.cpp | 50 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 52 | ||||
-rw-r--r-- | src/hir_typeck/impl_ref.hpp | 9 | ||||
-rw-r--r-- | src/main.cpp | 1 |
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);
});
|