summaryrefslogtreecommitdiff
path: root/src/hir_typeck
diff options
context:
space:
mode:
authorJohn Hodge (bugs) <tpg@mutabah.net>2017-06-04 21:23:24 +0800
committerJohn Hodge (bugs) <tpg@mutabah.net>2017-06-04 21:23:24 +0800
commit83dbb728f62306d2e43b2688dd0f2d320fd5b038 (patch)
treea064267bdf8d0455ed725140abfcbed3e04b2d4a /src/hir_typeck
parent0b9fd0014c8f32ecf299dae2ad1811dfb484af46 (diff)
parentf19c75571c48588fb3816e8eb5b96f03474fbdf5 (diff)
downloadmrust-83dbb728f62306d2e43b2688dd0f2d320fd5b038.tar.gz
Merge branch 'master' of https://github.com/thepowersgang/mrustc
Diffstat (limited to 'src/hir_typeck')
-rw-r--r--src/hir_typeck/expr_check.cpp72
-rw-r--r--src/hir_typeck/expr_cs.cpp146
-rw-r--r--src/hir_typeck/helpers.cpp112
-rw-r--r--src/hir_typeck/helpers.hpp2
-rw-r--r--src/hir_typeck/static.cpp237
-rw-r--r--src/hir_typeck/static.hpp2
6 files changed, 514 insertions, 57 deletions
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp
index 1b4317a6..fe67865f 100644
--- a/src/hir_typeck/expr_check.cpp
+++ b/src/hir_typeck/expr_check.cpp
@@ -22,12 +22,15 @@ namespace {
const ::HIR::TypeRef& ret_type;
::std::vector< const ::HIR::TypeRef*> closure_ret_types;
+ ::HIR::SimplePath m_lang_Index;
+
public:
ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type):
m_resolve(res),
//m_args(args),
ret_type(ret_type)
{
+ m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index");
}
void visit_root(::HIR::ExprPtr& node_ptr)
@@ -255,8 +258,7 @@ namespace {
{
TRACE_FUNCTION_F(&node << " ... [ ... ]");
check_associated_type(node.span(),
- node.m_res_type,
- this->get_lang_item_path(node.span(), "index"), { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target"
+ node.m_res_type, m_lang_Index, { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target"
);
node.m_value->visit( *this );
@@ -333,7 +335,10 @@ namespace {
const auto& src_ty = node.m_value->m_res_type;
const auto& dst_ty = node.m_res_type;
- if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() )
+ if( src_ty == dst_ty )
+ {
+ }
+ else if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() )
{
const auto& se = src_ty.m_data.as_Borrow();
const auto& de = dst_ty.m_data.as_Borrow();
@@ -363,10 +368,20 @@ namespace {
void visit(::HIR::ExprNode_Deref& node) override
{
TRACE_FUNCTION_F(&node << " *...");
- check_associated_type(node.span(),
- node.m_res_type,
- this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target"
- );
+ const auto& ty = node.m_value->m_res_type;
+
+ if( ty.m_data.is_Pointer() ) {
+ check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Pointer().inner);
+ }
+ else if( ty.m_data.is_Borrow() ) {
+ check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Borrow().inner);
+ }
+ else {
+ check_associated_type(node.span(),
+ node.m_res_type,
+ this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target"
+ );
+ }
node.m_value->visit( *this );
}
@@ -473,6 +488,14 @@ namespace {
TODO(sp, "Union in StructLiteral");
),
(Struct,
+ if( e->m_data.is_Unit() )
+ {
+ ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like struct");
+ ASSERT_BUG(node.span(), ! node.m_base_value, "Values provided for unit-like struct");
+ return ;
+ }
+
+ ASSERT_BUG(node.span(), e->m_data.is_Named(), "StructLiteral not pointing to a braced struct, instead " << e->m_data.tag_str() << " - " << ty);
fields_ptr = &e->m_data.as_Named();
)
)
@@ -704,6 +727,9 @@ namespace {
cache.m_monomorph_cb = mv$(monomorph_cb);
// Bounds
+ for(size_t i = 0; i < cache.m_fcn_params->m_types.size(); i ++)
+ {
+ }
for(const auto& bound : cache.m_fcn_params->m_bounds)
{
TU_MATCH(::HIR::GenericBound, (bound), (be),
@@ -713,7 +739,10 @@ namespace {
),
(TraitBound,
auto real_type = monomorphise_type_with(sp, be.type, cache.m_monomorph_cb);
+ m_resolve.expand_associated_types(sp, real_type);
auto real_trait = monomorphise_genericpath_with(sp, be.trait.m_path, cache.m_monomorph_cb, false);
+ for(auto& t : real_trait.m_params.m_types)
+ m_resolve.expand_associated_types(sp, t);
DEBUG("Bound " << be.type << ": " << be.trait);
DEBUG("= (" << real_type << ": " << real_trait << ")");
const auto& trait_params = real_trait.m_params;
@@ -728,6 +757,7 @@ namespace {
ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait);
auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true);
+ m_resolve.expand_associated_types(sp, other_ty);
check_associated_type(sp, other_ty, type_trait_path.m_path, type_trait_path.m_params, real_type, assoc.first.c_str());
}
@@ -992,10 +1022,29 @@ namespace {
const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ity, const char* name
) const
{
- // TODO: Actually check.
- #if 0
- bool found = m_resolve.find_impl(sp, trait, &params, ity, [&](auto impl, bool fuzzy){
-
+ if( trait == m_lang_Index && ity.m_data.is_Array() ) {
+ if(name)
+ {
+ if( res != *ity.m_data.as_Array().inner ) {
+ ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << *ity.m_data.as_Array().inner);
+ }
+ }
+ return ;
+ }
+ bool found = m_resolve.find_impl(sp, trait, &params, ity, [&](auto impl, bool fuzzy) {
+ if( name )
+ {
+ auto atyv = impl.get_type(name);
+ m_resolve.expand_associated_types(sp, atyv);
+ if( atyv == ::HIR::TypeRef() )
+ {
+ // TODO: Check that `res` is <ity as trait>::name
+ }
+ else if( res != atyv )
+ {
+ ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << atyv);
+ }
+ }
return true;
});
@@ -1003,7 +1052,6 @@ namespace {
{
ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity);
}
- #endif
}
const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 2388d078..eb922414 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -1061,6 +1061,7 @@ namespace {
for( auto& val : node.m_args ) {
this->context.add_ivars( val->m_res_type );
}
+ this->context.m_ivars.add_ivars_params(node.m_path.m_params);
// - Create ivars in path, and set result type
const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path);
@@ -1131,6 +1132,7 @@ namespace {
void visit(::HIR::ExprNode_StructLiteral& node) override
{
TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]");
+ this->add_ivars_generic_path(node.span(), node.m_path);
for( auto& val : node.m_values ) {
this->context.add_ivars( val.second->m_res_type );
}
@@ -1155,6 +1157,12 @@ namespace {
const auto& enm = *e;
auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; });
assert(it != enm.m_variants.end());
+ if( it->second.is_Unit() || it->second.is_Value() || it->second.is_Tuple() ) {
+ ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like variant");
+ ASSERT_BUG(node.span(), ! node.m_base_value, "Values provided for unit-like variant");
+ return ;
+ }
+ ASSERT_BUG(node.span(), it->second.is_Struct(), "_StructLiteral for non-struct variant - " << node.m_path);
fields_ptr = &it->second.as_Struct();
generics = &enm.m_params;
),
@@ -1162,6 +1170,18 @@ namespace {
TODO(node.span(), "StructLiteral of a union - " << ty);
),
(Struct,
+ if( e->m_data.is_Unit() || e->m_data.is_Tuple() )
+ {
+ ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like struct");
+
+ if( node.m_base_value ) {
+ auto _ = this->push_inner_coerce_scoped(false);
+ node.m_base_value->visit( *this );
+ }
+ return ;
+ }
+
+ ASSERT_BUG(node.span(), e->m_data.is_Named(), "StructLiteral not pointing to a braced struct, instead " << e->m_data.tag_str() << " - " << ty);
fields_ptr = &e->m_data.as_Named();
generics = &e->m_params;
)
@@ -1208,7 +1228,7 @@ namespace {
}
des_ty = &des_ty_cache;
}
- this->equate_types_inner_coerce(node.span(), *des_ty, val.second);
+ this->context.equate_types_coerce(node.span(), *des_ty, val.second);
}
// Convert bounds on the type into rules
@@ -3390,7 +3410,8 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
context.equate_types(sp, type, ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef(::HIR::CoreType::Str) ));
),
(ByteString,
- context.equate_types(sp, type, ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef::new_slice(::HIR::CoreType::U8) ));
+ // NOTE: Matches both &[u8] and &[u8; N], so doesn't provide type information
+ // TODO: Check the type.
),
(Named,
// TODO: Get type of the value and equate it
@@ -3730,10 +3751,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
this->add_ivars_params( e.path.m_params );
this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+ if( e.sub_patterns.empty() )
+ return ;
+
assert(e.binding);
const auto& str = *e.binding;
+
// - assert check from earlier pass
- assert( str.m_data.is_Named() );
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct");
const auto& sd = str.m_data.as_Named();
const auto& params = e.path.m_params;
@@ -3806,6 +3831,9 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
}
+ if( e.sub_patterns.empty() )
+ return ;
+
assert(e.binding_ptr);
const auto& enm = *e.binding_ptr;
const auto& var = enm.m_variants[e.binding_idx].second;
@@ -4123,22 +4151,35 @@ namespace {
//}
context.possible_equate_type_unsize_to(r_e.index, ty_dst);
context.possible_equate_type_unsize_from(l_e.index, ty_src);
- DEBUG("- Infer, add possibility");
+ DEBUG("- Both infer, add possibility");
return false;
}
// If the source is '_', we can't know yet
TU_IFLET(::HIR::TypeRef::Data, ty_src.m_data, Infer, r_e,
- // TODO: If the source is a literal, and the destination isn't a TraitObject, equate.
- // - Except if it's known to be a primitive
- //if( r_e.ty_class != ::HIR::InferClass::None ) {
- // context.equate_types(sp, ty_dst, ty_src);
- // return true;
- //}
- context.possible_equate_type_unsize_to(r_e.index, ty_dst);
- DEBUG("- Infer, add possibility");
- return false;
+ // No avaliable information, add a possible unsize
+ if( r_e.ty_class == ::HIR::InferClass::None || r_e.ty_class == ::HIR::InferClass::Diverge )
+ {
+ // Possibility
+ context.possible_equate_type_unsize_to(r_e.index, ty_dst);
+ DEBUG("- Infer, add possibility");
+ return false;
+ }
+ // Destination is infer, fall through to next TU_IFLET
+ else if( ty_dst.m_data.is_Infer() )
+ {
+ }
+ // Destination is a TraitObject, fall through to doing an impl search
+ else if( ty_dst.m_data.is_TraitObject() )
+ {
+ }
+ // Otherwise, they have to be equal
+ else
+ {
+ context.equate_types(sp, ty_dst, ty_src);
+ return true;
+ }
)
TU_IFLET(::HIR::TypeRef::Data, ty_dst.m_data, Infer, l_e,
@@ -4155,8 +4196,16 @@ namespace {
return true;
}
+ // If the source can't unsize, equate
+ if( const auto* te = ty_src.m_data.opt_Slice() )
+ {
+ (void)te;
+ context.equate_types(sp, ty_dst, ty_src);
+ return true;
+ }
+
context.possible_equate_type_unsize_from(l_e.index, ty_src);
- DEBUG("- Infer, add possibility");
+ DEBUG("- Dest infer, add possibility");
return false;
)
@@ -4702,12 +4751,15 @@ namespace {
}
// TODO: Can this can unsize as well as convert to raw?
+ // - It _can_ unsize, TODO:
context.equate_types(sp, *l_e.inner, *s_e.inner);
// Add downcast
auto span = node_ptr->span();
node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), ty_dst.clone() ));
node_ptr->m_res_type = ty_dst.clone();
+ // TODO: Add a coerce of src->&dst_inner
+
context.m_ivars.mark_change();
return true;
)
@@ -4908,8 +4960,28 @@ namespace {
else {
// No equivalence added
}
- // - Fall through and search for the impl
- DEBUG("- Unsize, no ivar equivalence");
+
+ // TODO: If this was a compiler-inserted bound (from a coercion rule), then do deref checks
+#if 0
+ {
+ ::HIR::TypeRef tmp_ty;
+ const ::HIR::TypeRef* ty_ptr = &src_ty;
+ while( (ty_ptr = context.m_resolve.autoderef(sp, *ty_ptr, tmp_ty)) )
+ {
+ const auto& cur_ty = context.m_ivars.get_type(*ty_ptr);
+ if( cur_ty.m_data.is_Infer() ) {
+ break;
+ }
+ auto cmp = dst_ty.compare_with_placeholders(sp, cur_ty, context.m_ivars.callback_resolve_infer());
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ // TODO: This is a deref coercion, so what can actually be done?
+ TODO(sp, "Handle Unsize with deref - " << src_ty << " -> " << dst_ty);
+ }
+ }
+ }
+#endif
+ DEBUG("- Unsize, no deref or ivar");
}
if( v.trait == context.m_crate.get_lang_item_path(sp, "coerce_unsized") )
{
@@ -4974,7 +5046,7 @@ namespace {
// > This makes `let v: usize = !0;` work without special cases
auto cmp2 = v.left_ty.compare_with_placeholders(sp, out_ty, context.m_ivars.callback_resolve_infer());
if( cmp2 == ::HIR::Compare::Unequal ) {
- DEBUG("- (fail) known result can't match (" << context.m_ivars.fmt_type(v.left_ty) << " and " << context.m_ivars.fmt_type(out_ty) << ")");
+ DEBUG("[check_associated] - (fail) known result can't match (" << context.m_ivars.fmt_type(v.left_ty) << " and " << context.m_ivars.fmt_type(out_ty) << ")");
return false;
}
// if solid or fuzzy, leave as-is
@@ -4993,9 +5065,10 @@ namespace {
}
else {
count += 1;
- DEBUG("- (possible) " << impl);
+ DEBUG("[check_associated] - (possible) " << impl);
if( possible_impl_ty == ::HIR::TypeRef() ) {
+ DEBUG("[check_associated] First - " << impl);
possible_impl_ty = impl.get_impl_type();
possible_params = impl.get_trait_params();
best_impl = mv$(impl);
@@ -5006,27 +5079,33 @@ namespace {
// NOTE: `overlaps_with` (should be) reflective
else if( impl.overlaps_with(best_impl) )
{
- DEBUG("- overlaps with " << best_impl);
+ DEBUG("[check_associated] - Overlaps with existing - " << best_impl);
+ // if not more specific than the existing best, ignore.
if( ! impl.more_specific_than(best_impl) )
{
+ DEBUG("[check_associated] - Less specific than existing");
+ // NOTE: This picks the _least_ specific impl
possible_impl_ty = impl.get_impl_type();
possible_params = impl.get_trait_params();
best_impl = mv$(impl);
count -= 1;
}
+ // If the existing best is not more specific than the new one, use the new one
else if( ! best_impl.more_specific_than(impl) )
{
- // Ignore
+ DEBUG("[check_associated] - More specific than existing - " << impl);
count -= 1;
}
else
{
- DEBUG("> Neither is more specific. Error?");
+ // Supposedly, `more_specific_than` should be reflexive...
+ DEBUG("[check_associated] > Neither is more specific. Error?");
}
}
else
{
// Disjoint impls.
+ DEBUG("[check_associated] Disjoint impl -" << impl);
}
#endif
@@ -5602,6 +5681,31 @@ namespace {
// TODO: Monomorphise this type replacing mentions of the current ivar with the replacement?
+#if 0 // NOTE: The following shouldn't happen
+ if( bound.trait == context.m_crate.get_lang_item_path(sp, "unsize") /* && bound.is_from_coerce*/ )
+ {
+ bool possible = false;
+
+ ::HIR::TypeRef tmp_ty;
+ const ::HIR::TypeRef* ty_ptr = &new_ty;
+ while( (ty_ptr = context.m_resolve.autoderef(sp, *ty_ptr, tmp_ty)) )
+ {
+ const auto& cur_ty = context.get_type(*ty_ptr);
+ if( cur_ty.m_data.is_Infer() ) {
+ break;
+ }
+ auto cmp = ty_l.compare_with_placeholders(sp, cur_ty, context.m_ivars.callback_resolve_infer());
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ possible = true;
+ break;
+ }
+ }
+ if( possible )
+ continue ;
+ }
+#endif
+
// Search for any trait impl that could match this,
bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;});
if( !has ) {
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index a1c64bec..a3fe9b1c 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -469,6 +469,8 @@ void HMTypeInferrence::add_ivars(::HIR::TypeRef& type)
(TraitObject,
// Iterate all paths
this->add_ivars_params(e.m_trait.m_path.m_params);
+ for(auto& aty : e.m_trait.m_type_bounds)
+ this->add_ivars(aty.second);
for(auto& marker : e.m_markers)
this->add_ivars_params(marker.m_params);
),
@@ -1079,25 +1081,13 @@ bool TraitResolution::find_trait_impls(const Span& sp,
const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut");
if( trait == lang_Sized ) {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e),
- (
- // Any unknown - it's sized
- ),
- (Primitive,
- if( e == ::HIR::CoreType::Str )
- return false;
- ),
- (Slice,
- return false;
- ),
- (Path,
- // ... TODO (Search the innards or bounds)
- ),
- (TraitObject,
+ auto cmp = type_is_sized(sp, type);
+ if( cmp != ::HIR::Compare::Unequal ) {
+ return callback( ImplRef(&type, &null_params, &null_assoc), cmp );
+ }
+ else {
return false;
- )
- )
- return callback( ImplRef(&type, &null_params, &null_assoc), ::HIR::Compare::Equal );
+ }
}
if( trait == lang_Copy ) {
@@ -2155,7 +2145,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple
if( e.trait.m_path.m_path == trait ) {
// Check against `params`
- DEBUG("Checking " << params << " vs " << b_params);
+ DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params);
auto ord = cmp;
ord &= this->compare_pp(sp, b_params, params);
if( ord == ::HIR::Compare::Unequal )
@@ -2163,6 +2153,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple
if( ord == ::HIR::Compare::Fuzzy ) {
DEBUG("Fuzzy match");
}
+ DEBUG("[find_trait_impls_bound] Match " << b);
// Hand off to the closure, and return true if it does
// TODO: The type bounds are only the types that are specified.
if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) {
@@ -2814,6 +2805,23 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
)
}
+ for(size_t i = 0; i < impl_params_def.m_types.size(); i ++)
+ {
+ if( impl_params_def.m_types.at(i).m_is_sized )
+ {
+ if( impl_params[i] ) {
+ auto cmp = type_is_sized(sp, *impl_params[i]);
+ if( cmp == ::HIR::Compare::Unequal )
+ {
+ return ::HIR::Compare::Unequal;
+ }
+ }
+ else {
+ // TODO: Set match to fuzzy?
+ }
+ }
+ }
+
return match;
}
@@ -2897,6 +2905,66 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa
return false;
}
+::HIR::Compare TraitResolution::type_is_sized(const Span& sp, const ::HIR::TypeRef& type) const
+{
+ TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e),
+ (
+ // Any unknown - it's sized
+ ),
+ (Infer,
+ switch(e.ty_class)
+ {
+ case ::HIR::InferClass::Integer:
+ case ::HIR::InferClass::Float:
+ return ::HIR::Compare::Equal;
+ default:
+ return ::HIR::Compare::Fuzzy;
+ }
+ ),
+ (Primitive,
+ if( e == ::HIR::CoreType::Str )
+ return ::HIR::Compare::Unequal;
+ ),
+ (Slice,
+ return ::HIR::Compare::Unequal;
+ ),
+ (Path,
+ // ... TODO (Search the innards or bounds)
+ TU_MATCHA( (e.binding), (pb),
+ (Unbound,
+ //
+ ),
+ (Opaque,
+ // TODO: Check bounds
+ ),
+ (Enum,
+ // HAS to be Sized
+ ),
+ (Union,
+ // Pretty sure unions are Sized
+ ),
+ (Struct,
+ // Possibly not sized
+ switch( pb->m_markings.dst_type )
+ {
+ case ::HIR::TraitMarkings::DstType::None:
+ break;
+ case ::HIR::TraitMarkings::DstType::Possible:
+ // TODO: Check sized-ness of the unsized param/field
+ break;
+ case ::HIR::TraitMarkings::DstType::Slice:
+ case ::HIR::TraitMarkings::DstType::TraitObject:
+ return ::HIR::Compare::Unequal;
+ }
+ )
+ )
+ ),
+ (TraitObject,
+ return ::HIR::Compare::Unequal;
+ )
+ )
+ return ::HIR::Compare::Equal;
+}
::HIR::Compare TraitResolution::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const
{
const auto& type = this->m_ivars.get_type(ty);
@@ -3284,6 +3352,12 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty
else {
bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](auto impls, auto match) {
tmp_type = impls.get_type("Target");
+ if( tmp_type == ::HIR::TypeRef() )
+ {
+ tmp_type = ::HIR::Path( ty.clone(), this->m_crate.get_lang_item_path(sp, "deref"), "Target" );
+ tmp_type.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ DEBUG("Deref " << ty << " into " << tmp_type);
return true;
});
if( succ ) {
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index b7e6ca38..d715905c 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -265,7 +265,9 @@ public:
bool trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, AllowedReceivers ar, ::HIR::GenericPath& out_path) const;
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_sized(const Span& sp, const ::HIR::TypeRef& ty) 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 {
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp
index 8baa2557..d8b692c9 100644
--- a/src/hir_typeck/static.cpp
+++ b/src/hir_typeck/static.cpp
@@ -109,11 +109,13 @@ bool StaticTraitResolve::find_impl(
return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
}
}
- //else if( trait_path == m_lang_Unsize ) {
- // if( true ) {
- // return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
- // }
- //}
+ else if( trait_path == m_lang_Unsize ) {
+ ASSERT_BUG(sp, trait_params, "TODO: Support no params for Unzie");
+ const auto& dst_ty = trait_params->m_types.at(0);
+ if( this->can_unsize(sp, dst_ty, type) ) {
+ return found_cb( ImplRef(&type, trait_params, &null_assoc), false );
+ }
+ }
}
// --- MAGIC IMPLS ---
@@ -1204,6 +1206,43 @@ bool StaticTraitResolve::iterate_bounds( ::std::function<bool(const ::HIR::Gener
}
return false;
}
+
+
+bool StaticTraitResolve::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const
+{
+ const auto& trait_ref = m_crate.get_trait_by_path(sp, pe.trait.m_path);
+ ASSERT_BUG(sp, trait_ref.m_types.count( pe.item ) != 0, "Trait " << pe.trait.m_path << " doesn't contain an associated type " << pe.item);
+ const auto& aty_def = trait_ref.m_types.find(pe.item)->second;
+
+ for(const auto& bound : aty_def.m_trait_bounds)
+ {
+ if( cb(bound) )
+ return true;
+ }
+ // Search `<Self as Trait>::Name` bounds on the trait itself
+ for(const auto& bound : trait_ref.m_params.m_bounds)
+ {
+ if( ! bound.is_TraitBound() ) continue ;
+ const auto& be = bound.as_TraitBound();
+
+ if( ! be.type.m_data.is_Path() ) continue ;
+ if( ! be.type.m_data.as_Path().binding.is_Opaque() ) continue ;
+
+ const auto& be_type_pe = be.type.m_data.as_Path().path.m_data.as_UfcsKnown();
+ if( *be_type_pe.type != ::HIR::TypeRef("Self", 0xFFFF) )
+ continue ;
+ if( be_type_pe.trait.m_path != pe.trait.m_path )
+ continue ;
+ if( be_type_pe.item != pe.item )
+ continue ;
+
+ if( cb(be.trait) )
+ return true;
+ }
+
+ return false;
+}
+
// -------------------------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------------------------
@@ -1435,6 +1474,194 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty)
throw "";
}
+bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const
+{
+ TRACE_FUNCTION_F(dst_ty << " <- " << src_ty);
+
+ ASSERT_BUG(sp, !dst_ty.m_data.is_Infer(), "_ seen after inferrence - " << dst_ty);
+ ASSERT_BUG(sp, !src_ty.m_data.is_Infer(), "_ seen after inferrence - " << src_ty);
+
+ {
+ //ASSERT_BUG(sp, dst_ty != src_ty, "Equal types for can_unsize - " << dst_ty << " <-" << src_ty );
+ if( dst_ty == src_ty )
+ return true;
+ }
+
+ {
+ 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 != m_lang_Unsize)
+ return false;
+ const auto& be_dst = be.trait.m_path.m_params.m_types.at(0);
+
+ if( src_ty != be.type ) return false;
+ if( dst_ty != be_dst ) return false;
+ return true;
+ });
+ if( found_bound )
+ {
+ return ::HIR::Compare::Equal;
+ }
+ }
+
+ // Associated types, check the bounds in the trait.
+ if( src_ty.m_data.is_Path() && src_ty.m_data.as_Path().path.m_data.is_UfcsKnown() )
+ {
+ const auto& pe = src_ty.m_data.as_Path().path.m_data.as_UfcsKnown();
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr);
+ auto found_bound = this->iterate_aty_bounds(sp, pe, [&](const ::HIR::TraitPath& bound) {
+ if( bound.m_path.m_path != m_lang_Unsize )
+ return false;
+ const auto& be_dst_tpl = bound.m_path.m_params.m_types.at(0);
+ ::HIR::TypeRef tmp_ty;
+ const auto& be_dst = (monomorphise_type_needed(be_dst_tpl) ? tmp_ty = monomorphise_type_with(sp, be_dst_tpl, monomorph_cb) : be_dst_tpl);
+
+ if( dst_ty != be_dst ) return false;
+ return true;
+ });
+ if( found_bound )
+ {
+ return true;
+ }
+ }
+
+ // 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 false;
+ }
+ 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 = dst_gp.m_params.m_types.at(str.m_markings.unsized_param);
+ const auto& src_inner = src_gp.m_params.m_types.at(str.m_markings.unsized_param);
+ return this->can_unsize(sp, dst_inner, src_inner);
+ }
+ else
+ {
+ DEBUG("Can't Unsize, destination and source are different structs");
+ return false;
+ }
+ }
+ }
+
+ // (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() )
+ {
+ // 1. Data trait must be the same
+ 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)
+ {
+ bool found = false;
+ for(const auto& omt : se->m_markers) {
+ if( omt == mt ) {
+ found = true;
+ break;
+ }
+ }
+ if( !found ) {
+ // Return early.
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool good;
+
+ ::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 = false;
+ find_impl(sp, de->m_trait.m_path.m_path, de->m_trait.m_path.m_params, src_ty,
+ [&](const auto impl, auto fuzz) {
+ //ASSERT_BUG(sp, !fuzz, "Fuzzy match in can_unsize - " << dst_ty << " <- " << src_ty << " - " << impl);
+ good = true;
+ 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 = ::HIR::TypeRef::new_path( mv$(p), {} );
+ }
+ this->expand_associated_types(sp, atyv);
+ if( aty.second != atyv ) {
+ good = false;
+ DEBUG("ATY " << aty.first << " mismatch - " << aty.second << " != " << atyv);
+ }
+ }
+ return true;
+ });
+ }
+
+ // Then markers
+ auto cb = [&](const auto impl, auto ){
+ 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 &= this->find_impl(sp, marker.m_path, marker.m_params, src_ty, cb);
+ }
+
+ return good;
+ }
+
+ // [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);
+ return *se->inner == *de->inner;
+ }
+ }
+
+ DEBUG("Can't unsize, no rules matched");
+ return ::HIR::Compare::Unequal;
+
+}
+
bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const
{
// If `T: Copy`, then it can't need drop glue
diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp
index 16302218..4c094218 100644
--- a/src/hir_typeck/static.hpp
+++ b/src/hir_typeck/static.hpp
@@ -170,6 +170,7 @@ public:
) const;
///
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;
+ bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const;
// --------------
@@ -177,6 +178,7 @@ public:
// -------------
bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const;
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;
/// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop
bool type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const;