summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hir/deserialise.cpp1
-rw-r--r--src/hir/hir.hpp1
-rw-r--r--src/hir/serialise.cpp1
-rw-r--r--src/hir_conv/markings.cpp30
-rw-r--r--src/hir_typeck/expr_cs.cpp44
-rw-r--r--src/hir_typeck/helpers.cpp362
-rw-r--r--src/hir_typeck/helpers.hpp7
7 files changed, 315 insertions, 131 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 19306a63..f4409310 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -586,6 +586,7 @@ namespace {
m.dst_type = static_cast< ::HIR::TraitMarkings::DstType>( m_in.read_tag() );
m.coerce_unsized_index = m_in.read_count( );
m.unsized_field = m_in.read_count( );
+ m.unsized_param = m_in.read_count();
// TODO: auto_impls
return m;
}
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index b7d116e3..51235c7d 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -177,6 +177,7 @@ struct TraitMarkings
TraitObject, // (Trait)
} dst_type;
unsigned int unsized_field = ~0u;
+ unsigned int unsized_param = ~0u;
/// `true` if there is a Copy impl
bool is_copy = false;
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index e5264ae2..77e17dba 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -864,6 +864,7 @@ namespace {
m_out.write_tag( static_cast<unsigned int>(m.dst_type) );
m_out.write_count( m.coerce_unsized_index );
m_out.write_count( m.unsized_field );
+ m_out.write_count( m.unsized_param );
// TODO: auto_impls
}
diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp
index a294f47b..4550bef5 100644
--- a/src/hir_conv/markings.cpp
+++ b/src/hir_conv/markings.cpp
@@ -43,6 +43,33 @@ public:
{
str.m_markings.unsized_field = (str.m_data.is_Tuple() ? str.m_data.as_Tuple().size()-1 : str.m_data.as_Named().size()-1);
}
+
+ // Rules:
+ // - A type parameter must be ?Sized
+ // - That type parameter must only be used as part of the last field, and only once
+ // - If the final field isn't the parameter, it must also impl Unsize
+
+ // HACK: Just determine what ?Sized parameter is controlling the sized-ness
+ if( str.m_markings.dst_type == ::HIR::TraitMarkings::DstType::Possible )
+ {
+ auto& last_field_ty = (str.m_data.is_Tuple() ? str.m_data.as_Tuple().back().ent : str.m_data.as_Named().back().second.ent);
+ auto ty = ::HIR::TypeRef("", 0);
+ for(size_t i = 0; i < str.m_params.m_types.size(); i++)
+ {
+ const auto& param = str.m_params.m_types[i];
+ auto ty = ::HIR::TypeRef(param.m_name, i);
+ if( !param.m_is_sized )
+ {
+ if( visit_ty_with(last_field_ty, [&](const auto& t){ return t == ty; }) )
+ {
+ assert(str.m_markings.unsized_param == ~0u);
+ str.m_markings.unsized_param = i;
+ }
+ }
+ }
+ ASSERT_BUG(Span(), str.m_markings.unsized_param != ~0u, "No unsized param for type " << ip);
+ str.m_markings.can_unsize = true;
+ }
}
void visit_trait(::HIR::ItemPath ip, ::HIR::Trait& tr) override
@@ -212,6 +239,7 @@ public:
::HIR::TraitMarkings::DstType get_field_dst_type(const ::HIR::TypeRef& ty, const ::HIR::GenericParams& inner_def, const ::HIR::GenericParams& params_def, const ::HIR::PathParams* params)
{
+ TRACE_FUNCTION_F("ty=" << ty);
// If the type is generic, and the pointed-to parameters is ?Sized, record as needing unsize
if( const auto* te = ty.m_data.opt_Generic() )
{
@@ -242,7 +270,7 @@ public:
// If the type is a struct, check it (recursively)
if( ! te->path.m_data.is_Generic() ) {
// Associated type, TODO: Check this better.
- return ::HIR::TraitMarkings::DstType::Possible;
+ return ::HIR::TraitMarkings::DstType::None;
}
else if( te->binding.is_Struct() ) {
const auto& params_tpl = te->path.m_data.as_Generic().m_params;
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 4a8f381a..1ac3b2f0 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -4415,14 +4415,11 @@ namespace {
// Search for Unsize
// - If `right`: ::core::marker::Unsize<`left`>
{
- const auto& lang_Unsize = context.m_crate.get_lang_item_path(sp, "unsize");
- ::HIR::PathParams pp;
- pp.m_types.push_back( ty_dst.clone() );
- bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, ty_src, [&](auto impl, auto cmp) {
- // TODO: Allow fuzzy match if only match
- return cmp == ::HIR::Compare::Equal;
+ auto cmp = context.m_resolve.can_unsize(sp, ty_dst, ty_src, [&](auto new_dst) {
+ // Equate these two types
});
- if( found ) {
+ if(cmp == ::HIR::Compare::Equal)
+ {
DEBUG("- Unsize " << &*node_ptr << " -> " << ty_dst);
auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone());
auto ty_dst_b2 = ty_dst_b.clone();
@@ -4431,18 +4428,27 @@ namespace {
return true;
}
- }
-
- if( ty_dst.m_data.is_Path() && ty_dst.m_data.as_Path().binding.is_Unbound() )
- {
- }
- else if( ty_src.m_data.is_Path() && ty_src.m_data.as_Path().binding.is_Unbound() )
- {
- }
- else if( ty_dst.compare_with_placeholders(sp, ty_src, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
- {
- context.equate_types(sp, ty_dst, ty_src);
- return true;
+ if(cmp == ::HIR::Compare::Unequal)
+ {
+ // No unsize possible, equate types
+ // - Only if they're not already fixed as unequal (that gets handled elsewhere)
+ if( ty_dst.m_data.is_Path() && ty_dst.m_data.as_Path().binding.is_Unbound() )
+ {
+ }
+ else if( ty_src.m_data.is_Path() && ty_src.m_data.as_Path().binding.is_Unbound() )
+ {
+ }
+ else if( ty_dst.compare_with_placeholders(sp, ty_src, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
+ {
+ context.equate_types(sp, ty_dst, ty_src);
+ return true;
+ }
+ }
+ if(cmp == ::HIR::Compare::Fuzzy)
+ {
+ // Not sure yet
+ return false;
+ }
}
// Keep trying
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index c29bc64b..33d26184 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -1075,66 +1075,26 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
// Magic Unsize impls to trait objects
- if( trait == lang_Unsize ) {
+ 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]);
- TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, TraitObject, e,
- // Magic impl if T: ThisTrait
- bool good;
-
- ::HIR::TypeRef::Data::Data_TraitObject tmp_e;
- tmp_e.m_trait.m_path = e.m_trait.m_path.m_path;
- ::HIR::Compare total_cmp = ::HIR::Compare::Equal;
- if( e.m_trait.m_path.m_path == ::HIR::SimplePath() ) {
- ASSERT_BUG(sp, e.m_markers.size() > 0, "TraitObject with no traits - " << dst_ty);
- good = true;
- }
- else {
- good = find_trait_impls(sp, e.m_trait.m_path.m_path, e.m_trait.m_path.m_params, ty,
- [&](const auto impl, auto cmp){
- if( cmp == ::HIR::Compare::Unequal )
- return false;
- total_cmp &= cmp;
- tmp_e.m_trait.m_path.m_params = impl.get_trait_params();
- for(const auto& aty : e.m_trait.m_type_bounds) {
- auto atyv = impl.get_type(aty.first.c_str());
- if( atyv == ::HIR::TypeRef() )
- {
- // Get the trait from which this associated type comes.
- // Insert a UfcsKnown path for that
- auto p = ::HIR::Path( ty.clone(), e.m_trait.m_path.clone(), aty.first );
- // Run EAT
- atyv = this->expand_associated_types( sp, ::HIR::TypeRef::new_path( mv$(p), {} ) );
- }
- tmp_e.m_trait.m_type_bounds[aty.first] = mv$(atyv);
- }
- return true;
- });
- }
- auto cb = [&](const auto impl, auto cmp){
- if( cmp == ::HIR::Compare::Unequal )
- return false;
- total_cmp &= cmp;
- tmp_e.m_markers.back().m_params = impl.get_trait_params();
- return true;
- };
- for(const auto& marker : e.m_markers)
- {
- if(!good) break;
- tmp_e.m_markers.push_back( marker.m_path );
- good &= find_trait_impls(sp, marker.m_path, marker.m_params, ty, cb);
- }
- if( good ) {
- ::HIR::PathParams real_params { ::HIR::TypeRef( ::HIR::TypeRef::Data(mv$(tmp_e)) ) };
- return callback( ImplRef(type.clone(), mv$(real_params), {}), total_cmp );
- }
- else {
- return false;
- }
- )
+ if( find_trait_impls_bound(sp, trait, params, type, callback) )
+ return true;
- // [T;N] -> [T] is handled down with array indexing
+ 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 );
+ };
+ 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
@@ -1278,23 +1238,6 @@ bool TraitResolution::find_trait_impls(const Span& sp,
*/
return false;
}
-
- // Unsize impl for arrays
- if( trait == lang_Unsize )
- {
- ASSERT_BUG(sp, params.m_types.size() == 1, "");
- const auto& dst_ty = m_ivars.get_type( params.m_types[0] );
-
- TU_IFLET(::HIR::TypeRef::Data, dst_ty.m_data, Slice, e2,
- auto cmp = e.inner->compare_with_placeholders(sp, *e2.inner, m_ivars.callback_resolve_infer());
- if( cmp != ::HIR::Compare::Unequal ) {
- ::HIR::PathParams pp;
- // - <[`array_inner`]> so it can be matched with the param by the caller
- pp.m_types.push_back( ::HIR::TypeRef::new_slice(e.inner->clone()) );
- return callback( ImplRef(type.clone(), mv$(pp), {}), cmp );
- }
- )
- }
)
@@ -1344,44 +1287,6 @@ bool TraitResolution::find_trait_impls(const Span& sp,
return rv;
}
- // Trait objects can unsize to a subset of their traits.
- if( trait == lang_Unsize )
- {
- ASSERT_BUG(sp, params.m_types.size() == 1, "");
- const auto& dst_ty = m_ivars.get_type( params.m_types[0] );
- if( ! dst_ty.m_data.is_TraitObject() ) {
- // If the destination isn't a trait object, don't even bother
- return false;
- }
- const auto& e2 = dst_ty.m_data.as_TraitObject();
-
- auto cmp = ::HIR::Compare::Equal;
-
- // TODO: Fuzzy compare
- if( e2.m_trait != e.m_trait ) {
- return false;
- }
- // The destination must have a strict subset of marker traits.
- const auto& src_markers = e.m_markers;
- const auto& dst_markers = e2.m_markers;
- for(const auto& mt : dst_markers)
- {
- // TODO: Fuzzy match
- bool found = false;
- for(const auto& omt : src_markers) {
- if( omt == mt ) {
- found = true;
- break;
- }
- }
- if( !found ) {
- // Return early.
- return false;
- }
- }
-
- return callback( ImplRef(&type, &e.m_trait.m_path.m_params, &e.m_trait.m_type_bounds), cmp );
- }
)
TU_IFLET(::HIR::TypeRef::Data, type.m_data, ErasedType, e,
@@ -3109,6 +3014,241 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa
)
)
}
+// 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.
+// - Returns Compare::Unequal if the unsize is impossibe (for any reason)
+//
+// Closure is called `get_new_type` is true, and the unsize is possible
+//
+// usecases:
+// - Checking for an impl as part of impl selection (return True/False/Maybe with required match for Maybe)
+// - Checking for an impl as part of typeck (return True/False/Maybe with unsize possibility OR required equality)
+::HIR::Compare TraitResolution::can_unsize(
+ const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty,
+ ::std::function<void(::HIR::TypeRef new_dst)>* new_type_callback,
+ ::std::function<void(const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src)>* infer_callback
+ ) const
+{
+ TRACE_FUNCTION_F(dst_ty << " <- " << src_ty);
+ const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize");
+
+ // 1. Test for type equality
+ {
+ auto cmp = dst_ty.compare_with_placeholders(sp, src_ty, m_ivars.callback_resolve_infer());
+ if( cmp == ::HIR::Compare::Equal )
+ {
+ return ::HIR::Compare::Unequal;
+ }
+ }
+
+ // 2. If either side is an ivar, fuzzy.
+ if( dst_ty.m_data.is_Infer() || src_ty.m_data.is_Infer() )
+ {
+ // Inform the caller that these two types could unsize to each other
+ // - This allows the coercions code to move the coercion rule up
+ if( infer_callback )
+ {
+ (*infer_callback)(dst_ty, src_ty);
+ }
+ return ::HIR::Compare::Fuzzy;
+ }
+
+ {
+ bool found_bound = this->iterate_bounds([&](const auto& gb){
+ if(!gb.is_TraitBound())
+ return false;
+ const auto& be = gb.as_TraitBound();
+ if(be.trait.m_path.m_path != lang_Unsize)
+ return false;
+ const auto& be_dst = be.trait.m_path.m_params.m_types.at(0);
+
+ auto cmp = src_ty.compare_with_placeholders(sp, be.type, m_ivars.callback_resolve_infer());
+ if(cmp == ::HIR::Compare::Unequal) return false;
+
+ cmp &= dst_ty.compare_with_placeholders(sp, be_dst, m_ivars.callback_resolve_infer());
+ if(cmp == ::HIR::Compare::Unequal) return false;
+
+ if( cmp != ::HIR::Compare::Equal )
+ {
+ TODO(sp, "Found bound " << dst_ty << "=" << be_dst << " <- " << src_ty << "=" << be.type);
+ }
+ return true;
+ });
+ if( found_bound )
+ {
+ return ::HIR::Compare::Equal;
+ }
+ }
+
+ // Struct<..., T, ...>: Unsize<Struct<..., U, ...>>
+ if( dst_ty.m_data.is_Path() && src_ty.m_data.is_Path() )
+ {
+ bool dst_is_unsizable = dst_ty.m_data.as_Path().binding.is_Struct() && dst_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize;
+ bool src_is_unsizable = src_ty.m_data.as_Path().binding.is_Struct() && src_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize;
+ if( dst_is_unsizable || src_is_unsizable )
+ {
+ DEBUG("Struct unsize? " << dst_ty << " <- " << src_ty);
+ const auto& str = *dst_ty.m_data.as_Path().binding.as_Struct();
+ const auto& dst_gp = dst_ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& src_gp = src_ty.m_data.as_Path().path.m_data.as_Generic();
+
+ if( dst_gp == src_gp )
+ {
+ DEBUG("Can't Unsize, destination and source are identical");
+ return ::HIR::Compare::Unequal;
+ }
+ else if( dst_gp.m_path == src_gp.m_path )
+ {
+ DEBUG("Checking for Unsize " << dst_gp << " <- " << src_gp);
+ // Structures are equal, add the requirement that the ?Sized parameter also impl Unsize
+ const auto& dst_inner = m_ivars.get_type( dst_gp.m_params.m_types.at(str.m_markings.unsized_param) );
+ const auto& src_inner = m_ivars.get_type( src_gp.m_params.m_types.at(str.m_markings.unsized_param) );
+
+ auto cb = [&](auto d){
+ assert(new_type_callback);
+
+ // Re-create structure with s/d
+ auto dst_gp_new = dst_gp.clone();
+ dst_gp_new.m_params.m_types.at(str.m_markings.unsized_param) = mv$(d);
+ (*new_type_callback)( ::HIR::TypeRef::new_path(mv$(dst_gp_new), &str) );
+ };
+ if( new_type_callback )
+ {
+ ::std::function<void(::HIR::TypeRef)> cb_p = cb;
+ return this->can_unsize(sp, dst_inner, src_inner, &cb_p, infer_callback);
+ }
+ else
+ {
+ return this->can_unsize(sp, dst_inner, src_inner, nullptr, infer_callback);
+ }
+ }
+ else
+ {
+ DEBUG("Can't Unsize, destination and source are different structs");
+ return ::HIR::Compare::Unequal;
+ }
+ }
+ }
+
+ // (Trait) <- Foo
+ if( const auto* de = dst_ty.m_data.opt_TraitObject() )
+ {
+ // TODO: Check if src_ty is !Sized
+ // - Only allowed if the source is a trait object with the same data trait and lesser bounds
+
+ DEBUG("TraitObject unsize? " << dst_ty << " <- " << src_ty);
+
+ // (Trait) <- (Trait+Foo)
+ if( const auto* se = src_ty.m_data.opt_TraitObject() )
+ {
+ auto rv = ::HIR::Compare::Equal;
+ // 1. Data trait must be the same (TODO: Fuzzy)
+ if( de->m_trait != se->m_trait )
+ {
+ return ::HIR::Compare::Unequal;
+ }
+
+ // 2. Destination markers must be a strict subset
+ for(const auto& mt : de->m_markers)
+ {
+ // TODO: Fuzzy match
+ bool found = false;
+ for(const auto& omt : se->m_markers) {
+ if( omt == mt ) {
+ found = true;
+ break;
+ }
+ }
+ if( !found ) {
+ // Return early.
+ return ::HIR::Compare::Unequal;
+ }
+ }
+
+ if( rv == ::HIR::Compare::Fuzzy && new_type_callback )
+ {
+ // TODO: Inner type
+ }
+ return ::HIR::Compare::Equal;
+ }
+
+ bool good;
+ ::HIR::Compare total_cmp = ::HIR::Compare::Equal;
+
+ ::HIR::TypeRef::Data::Data_TraitObject tmp_e;
+ tmp_e.m_trait.m_path = de->m_trait.m_path.m_path;
+
+ // Check data trait first.
+ if( de->m_trait.m_path.m_path == ::HIR::SimplePath() ) {
+ ASSERT_BUG(sp, de->m_markers.size() > 0, "TraitObject with no traits - " << dst_ty);
+ good = true;
+ }
+ else {
+ good = find_trait_impls(sp, de->m_trait.m_path.m_path, de->m_trait.m_path.m_params, src_ty,
+ [&](const auto impl, auto cmp) {
+ if( cmp == ::HIR::Compare::Unequal )
+ return false;
+ total_cmp &= cmp;
+ tmp_e.m_trait.m_path.m_params = impl.get_trait_params();
+ for(const auto& aty : de->m_trait.m_type_bounds) {
+ auto atyv = impl.get_type(aty.first.c_str());
+ if( atyv == ::HIR::TypeRef() )
+ {
+ // Get the trait from which this associated type comes.
+ // Insert a UfcsKnown path for that
+ auto p = ::HIR::Path( src_ty.clone(), de->m_trait.m_path.clone(), aty.first );
+ // Run EAT
+ atyv = this->expand_associated_types( sp, ::HIR::TypeRef::new_path( mv$(p), {} ) );
+ }
+ tmp_e.m_trait.m_type_bounds[aty.first] = mv$(atyv);
+ }
+ return true;
+ });
+ }
+
+ // Then markers
+ auto cb = [&](const auto impl, auto cmp){
+ if( cmp == ::HIR::Compare::Unequal )
+ return false;
+ total_cmp &= cmp;
+ tmp_e.m_markers.back().m_params = impl.get_trait_params();
+ return true;
+ };
+ for(const auto& marker : de->m_markers)
+ {
+ if(!good) break;
+ tmp_e.m_markers.push_back( marker.m_path );
+ good &= find_trait_impls(sp, marker.m_path, marker.m_params, src_ty, cb);
+ }
+
+ if( good && total_cmp == ::HIR::Compare::Fuzzy && new_type_callback )
+ {
+ (*new_type_callback)( ::HIR::TypeRef(mv$(tmp_e)) );
+ }
+ return total_cmp;
+ }
+
+ // [T] <- [T; n]
+ if( const auto* de = dst_ty.m_data.opt_Slice() )
+ {
+ if( const auto* se = src_ty.m_data.opt_Array() )
+ {
+ DEBUG("Array unsize? " << *de->inner << " <- " << *se->inner);
+ auto cmp = de->inner->compare_with_placeholders(sp, *se->inner, m_ivars.callback_resolve_infer());
+ // TODO: Indicate to caller that for this to be true, these two must be the same.
+ // - I.E. if true, equate these types
+ if(cmp == ::HIR::Compare::Fuzzy && new_type_callback)
+ {
+ (*new_type_callback)( ::HIR::TypeRef::new_slice( se->inner->clone() ) );
+ }
+ return cmp;
+ }
+ }
+
+ DEBUG("Can't unsize, no rules matched");
+ return ::HIR::Compare::Unequal;
+}
const ::HIR::TypeRef* TraitResolution::type_is_owned_box(const Span& sp, const ::HIR::TypeRef& ty) const
{
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index a1db0af9..1f63dbf4 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -265,6 +265,13 @@ public:
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;
::HIR::Compare type_is_copy(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
+ ::HIR::Compare can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty, ::std::function<void(::HIR::TypeRef new_dst)> new_type_callback) const {
+ return can_unsize(sp, dst_ty, src_ty, &new_type_callback);
+ }
+ ::HIR::Compare can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty, ::std::function<void(::HIR::TypeRef new_dst)>* new_type_callback, ::std::function<void(const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src)>* infer_callback=nullptr) const;
+
const ::HIR::TypeRef* type_is_owned_box(const Span& sp, const ::HIR::TypeRef& ty) const;
private: