summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-08-02 21:26:58 +0800
committerJohn Hodge <tpg@mutabah.net>2018-08-02 21:26:58 +0800
commitb2423dbde77141cced2a53c3a4f2e323ed8e4efa (patch)
tree87af38233e6860320f3245e6d531e31944e65a38
parentc3d14bb51bea1f2a6e917fb8359335772c52f6f4 (diff)
downloadmrust-b2423dbde77141cced2a53c3a4f2e323ed8e4efa.tar.gz
HIR Typecheck - Magic Clone impls
-rw-r--r--src/hir_typeck/expr_cs.cpp4
-rw-r--r--src/hir_typeck/helpers.cpp218
-rw-r--r--src/hir_typeck/helpers.hpp3
-rw-r--r--src/hir_typeck/static.cpp97
-rw-r--r--src/hir_typeck/static.hpp5
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;