diff options
author | John Hodge <tpg@mutabah.net> | 2018-08-02 21:26:58 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-08-02 21:26:58 +0800 |
commit | b2423dbde77141cced2a53c3a4f2e323ed8e4efa (patch) | |
tree | 87af38233e6860320f3245e6d531e31944e65a38 | |
parent | c3d14bb51bea1f2a6e917fb8359335772c52f6f4 (diff) | |
download | mrust-b2423dbde77141cced2a53c3a4f2e323ed8e4efa.tar.gz |
HIR Typecheck - Magic Clone impls
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 4 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 218 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 3 | ||||
-rw-r--r-- | src/hir_typeck/static.cpp | 97 | ||||
-rw-r--r-- | src/hir_typeck/static.hpp | 5 |
5 files changed, 270 insertions, 57 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 07f86d44..65bca2c0 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2155,8 +2155,8 @@ namespace { } ), (Borrow, - // Check class (must be equal) and type - if( s_e.type != e.type ) { + // Check class (destination must be weaker) and type + if( !(s_e.type >= e.type) ) { ERROR(sp, E0000, "Invalid cast from " << src_ty << " to " << tgt_ty); } const auto& src_inner = this->context.get_type(*s_e.inner); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 8f1f0685..a3991981 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1089,7 +1089,8 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data bool TraitResolution::find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ty, - t_cb_trait_impl_r callback + t_cb_trait_impl_r callback, + bool magic_trait_impls /*=true*/ ) const { static ::HIR::PathParams null_params; @@ -1110,6 +1111,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); + //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized"); const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); @@ -1118,23 +1120,37 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& trait_index = this->m_crate.get_lang_item_path(sp, "index"); const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut"); - if( trait == lang_Sized ) { - auto cmp = type_is_sized(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; + if( magic_trait_impls ) + { + if( trait == lang_Sized ) { + auto cmp = type_is_sized(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - } - if( trait == lang_Copy ) { - auto cmp = this->type_is_copy(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + if( trait == lang_Copy ) { + auto cmp = this->type_is_copy(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - else { - return false; + + if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") ) + { + auto cmp = this->type_is_clone(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } } @@ -1416,53 +1432,56 @@ bool TraitResolution::find_trait_impls(const Span& sp, } ) - // Magic Unsize impls to trait objects - if( trait == lang_Unsize ) + if( magic_trait_impls ) { - ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); - const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); + // Magic Unsize impls to trait objects + if( trait == lang_Unsize ) + { + ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); + const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); - if( find_trait_impls_bound(sp, trait, params, type, callback) ) - return true; + if( find_trait_impls_bound(sp, trait, params, type, callback) ) + return true; - bool rv = false; - auto cb = [&](auto new_dst) { - ::HIR::PathParams real_params { mv$(new_dst) }; - rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); - }; - //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) - //{ - // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); - // return rv; - //} - auto cmp = this->can_unsize(sp, dst_ty, type, cb); - if( cmp == ::HIR::Compare::Equal ) - { - assert(!rv); - rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + bool rv = false; + auto cb = [&](auto new_dst) { + ::HIR::PathParams real_params { mv$(new_dst) }; + rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); + }; + //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) + //{ + // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); + // return rv; + //} + auto cmp = this->can_unsize(sp, dst_ty, type, cb); + if( cmp == ::HIR::Compare::Equal ) + { + assert(!rv); + rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + } + return rv; } - return rv; - } - // Magical CoerceUnsized impls for various types - if( trait == lang_CoerceUnsized ) { - const auto& dst_ty = params.m_types.at(0); - // - `*mut T => *const T` - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, - TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, - if( de.type < e.type ) { - auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); - if( cmp != ::HIR::Compare::Unequal ) - { - ::HIR::PathParams pp; - pp.m_types.push_back( dst_ty.clone() ); - if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { - return true; + // Magical CoerceUnsized impls for various types + if( trait == lang_CoerceUnsized ) { + const auto& dst_ty = params.m_types.at(0); + // - `*mut T => *const T` + TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, + TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, + if( de.type < e.type ) { + auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + ::HIR::PathParams pp; + pp.m_types.push_back( dst_ty.clone() ); + if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { + return true; + } } } - } + ) ) - ) + } } // 1. Search generic params @@ -3169,6 +3188,97 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa ) ) } +::HIR::Compare TraitResolution::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + TRACE_FUNCTION_F(ty); + const auto& type = this->m_ivars.get_type(ty); + const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), + ( + // NOTE: Don't use find_trait_impls, because that calls this + bool is_fuzzy = false; + bool has_eq = find_trait_impls(sp, lang_Clone, ::HIR::PathParams{}, ty, [&](auto , auto c)->bool{ + switch(c) + { + case ::HIR::Compare::Equal: return true; + case ::HIR::Compare::Fuzzy: + is_fuzzy = true; + return false; + case ::HIR::Compare::Unequal: + return false; + } + throw ""; + }, false); + if( has_eq ) { + return ::HIR::Compare::Equal; + } + else if( is_fuzzy ) { + return ::HIR::Compare::Fuzzy; + } + else { + return ::HIR::Compare::Unequal; + } + ), + (Infer, + switch(e.ty_class) + { + case ::HIR::InferClass::Integer: + case ::HIR::InferClass::Float: + return ::HIR::Compare::Equal; + default: + DEBUG("Fuzzy Clone impl for ivar?"); + return ::HIR::Compare::Fuzzy; + } + ), + (Generic, + // TODO: Store this result - or even pre-calculate it. + return this->iterate_bounds([&](const auto& b)->bool { + TU_IFLET(::HIR::GenericBound, b, TraitBound, be, + if(be.type == ty) + { + if(be.trait.m_path == lang_Clone) + return true; + ::HIR::PathParams pp; + bool rv = this->find_named_trait_in_trait(sp, + lang_Clone,pp, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, type, + [&](const auto& , const auto&, const auto&)->bool { return true; } + ); + if(rv) + return true; + } + ) + return false; + }) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Primitive, + if( e == ::HIR::CoreType::Str ) + return ::HIR::Compare::Unequal; + return ::HIR::Compare::Equal; + ), + (Borrow, + return e.type == ::HIR::BorrowType::Shared ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Pointer, + return ::HIR::Compare::Equal; + ), + (Tuple, + auto rv = ::HIR::Compare::Equal; + for(const auto& sty : e) + rv &= type_is_clone(sp, sty); + return rv; + ), + (Slice, + return ::HIR::Compare::Unequal; + ), + (Function, + return ::HIR::Compare::Equal; + ), + (Array, + // TODO: Clone here? + return type_is_copy(sp, *e.inner); + ) + ) +} // Checks if a type can unsize to another // - Returns Compare::Equal if the unsize is possible and fully known // - Returns Compare::Fuzzy if the unsize is possible, but still unknown. diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 58688d6e..e7a917f4 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -207,7 +207,7 @@ public: typedef ::std::function<bool(ImplRef, ::HIR::Compare)> t_cb_trait_impl_r; /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const; + bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback, bool magic_trait_impls=true) const; /// Locate a named trait in the provied trait (either itself or as a parent trait) bool find_named_trait_in_trait(const Span& sp, @@ -283,6 +283,7 @@ public: ::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/static.cpp b/src/hir_typeck/static.cpp index cfa94dbb..016d86a0 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -104,6 +104,11 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); } } + else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) { + if( 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 ); @@ -1393,6 +1398,10 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) return true; ), (Closure, + if( TARGETVER_1_29 ) + { + // TODO: Auto-gerated impls + } return false; ), (Infer, @@ -1444,6 +1453,94 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) ) throw ""; } +bool StaticTraitResolve::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + if( !TARGETVER_1_29 ) BUG(sp, "Calling type_is_clone when not in 1.29 mode"); + + TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), + (Generic, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + { + return it->second; + } + } + bool rv = this->iterate_bounds([&](const auto& b)->bool { + auto pp = ::HIR::PathParams(); + return this->find_impl__check_bound(sp, m_lang_Clone, &pp, ty, [&](auto , bool ){ return true; }, b); + }); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Path, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + return it->second; + } + auto pp = ::HIR::PathParams(); + bool rv = this->find_impl(sp, m_lang_Clone, &pp, ty, [&](auto , bool){ return true; }, true); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Diverge, + // The ! type is kinda Copy/Clone ... + return true; + ), + (Closure, + // TODO: Auto-gerated impls + return false; + ), + (Infer, + // Shouldn't be hit + return false; + ), + (Borrow, + // Only shared &-ptrs are copy/clone + return (e.type == ::HIR::BorrowType::Shared); + ), + (Pointer, + // All raw pointers are Copy/Clone + return true; + ), + (Function, + // All function pointers are Copy/Clone + return true; + ), + (Primitive, + // All primitives (except the unsized `str`) are Copy/Clone + return e != ::HIR::CoreType::Str; + ), + (Array, + return e.size_val == 0 || type_is_clone(sp, *e.inner); + ), + (Slice, + // [T] isn't Sized, so isn't Copy ether + return false; + ), + (TraitObject, + // (Trait) isn't Sized, so isn't Copy ether + return false; + ), + (ErasedType, + for(const auto& trait : e.m_traits) + { + if( find_named_trait_in_trait(sp, m_lang_Clone, {}, *trait.m_trait_ptr, trait.m_path.m_path, trait.m_path.m_params, ty, [](const auto&, auto ){ }) ) { + return true; + } + } + return false; + ), + (Tuple, + for(const auto& ty : e) + if( !type_is_clone(sp, ty) ) + return false; + return true; + ) + ) + throw ""; +} bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const { diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 8c9cb9a6..ae429a3f 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -23,6 +23,7 @@ public: ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; ::HIR::SimplePath m_lang_Copy; + ::HIR::SimplePath m_lang_Clone; // 1.29 ::HIR::SimplePath m_lang_Drop; ::HIR::SimplePath m_lang_Sized; ::HIR::SimplePath m_lang_Unsize; @@ -34,6 +35,7 @@ public: private: mutable ::std::map< ::HIR::TypeRef, bool > m_copy_cache; + mutable ::std::map< ::HIR::TypeRef, bool > m_clone_cache; public: StaticTraitResolve(const ::HIR::Crate& crate): @@ -42,6 +44,8 @@ public: m_item_generics(nullptr) { m_lang_Copy = m_crate.get_lang_item_path_opt("copy"); + if( TARGETVER_1_29 ) + m_lang_Clone = m_crate.get_lang_item_path_opt("clone"); m_lang_Drop = m_crate.get_lang_item_path_opt("drop"); m_lang_Sized = m_crate.get_lang_item_path_opt("sized"); m_lang_Unsize = m_crate.get_lang_item_path_opt("unsize"); @@ -178,6 +182,7 @@ public: // Common bounds // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; + bool type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // 1.29 bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const; |