summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir_typeck/expr_cs.cpp163
-rw-r--r--src/hir_typeck/impl_ref.cpp46
-rw-r--r--src/hir_typeck/impl_ref.hpp3
3 files changed, 144 insertions, 68 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 6ced24c8..12e4c687 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -3416,15 +3416,24 @@ namespace {
// PROBLEM: This can false-negative leading to the types being falsely equated.
bool fuzzy_match = false;
+ ImplRef best_impl;
bool found = context.m_resolve.find_trait_impls(sp, lang_CoerceUnsized, pp, ty_src, [&](auto impl, auto cmp) {
DEBUG("[check_coerce] cmp=" << cmp << ", impl=" << impl);
// TODO: Allow fuzzy match if it's the only matching possibility?
- // - Recorded for now to know if a later pass is a good idea
+ // - Recorded for now to know if there could be a matching impl later
if( cmp == ::HIR::Compare::Fuzzy ) {
fuzzy_match = true;
+ if( impl.more_specific_than(best_impl) ) {
+ best_impl = mv$(impl);
+ }
+ else {
+ TODO(sp, "Equal specificity impls");
+ }
}
return cmp == ::HIR::Compare::Equal;
});
+ // TODO: If there was one fuzzy impl, emit an _Unsize and a trait bound.
+ // - Would this break if there's multiple coercion points in a flow (as there is no `T: Unsize<T>` to satisfy the case where the coercion wouldn't apply)
if( found )
{
DEBUG("- CoerceUnsize " << &*node_ptr << " -> " << ty_dst);
@@ -3435,9 +3444,21 @@ namespace {
}
if( fuzzy_match )
{
- const auto& span = sp;
- // TODO: Apply ivar possibilities between the parameters in `ty_src` and `ty_dst`
+ DEBUG("- best_impl = " << best_impl);
+ // TODO: Convert to a bound and emit an _Unsize (which may end up being a no-op)
+
+ #if 1
+
+ context.equate_types_assoc(sp, ::HIR::TypeRef(), lang_CoerceUnsized, ::make_vec1(ty_dst.clone()), ty_src, "");
+ node_ptr = NEWNODE( ty_dst.clone(), sp, _Unsize, mv$(node_ptr), ty_dst.clone() );
+ return true;
+
+ #else
+
+ const auto& span = sp; // new name, because `sp` becomes "source path"
+ // Apply ivar possibilities between the parameters in `ty_src` and `ty_dst`
// - Ideally, this equivalence would be done using the parameter known to be the pointer target
+ // TODO: Expand this to perform Unsize impl equating (same as `check_coerce_borrow`)?
if( ty_dst.m_data.is_Path() && ty_src.m_data.is_Path() )
{
const auto& dp = ty_dst.m_data.as_Path().path;
@@ -3487,11 +3508,8 @@ namespace {
}
}
}
- #if 1
DEBUG("- CoerceUnsize possible, trying later");
return false;
- #else
- DEBUG("- CoerceUnsize possible?");
#endif
}
}
@@ -3805,45 +3823,77 @@ namespace {
}
else
{
- BUG(sp, "");
+ BUG(sp, "Associated type rule with `is_operator` set but an incorrect parameter count");
}
}
- // HACK: If the LHS is an opqaue UfcsKnown for the same trait and item, equate the inner types
- #if 0
- TU_IFLET(::HIR::TypeRef::Data, v.left_ty.m_data, Path, e,
- if( e.binding.is_Opaque() )
- {
- TU_IFLET(::HIR::Path::Data, e.path.m_data, UfcsKnown, pe,
- if( pe.trait.m_path == v.trait && pe.item == v.name )
- {
- #if 0
- context.equate_types(sp, *pe.type, v.impl_ty);
- #else
- TU_IFLET(::HIR::TypeRef::Data, context.get_type(*pe.type).m_data, Infer, e2,
- //context.possible_equate_type_from(e2.index, v.impl_ty);
- //context.possible_equate_type_to(e2.index, v.impl_ty);
- return false;
- )
- else TU_IFLET(::HIR::TypeRef::Data, context.get_type(v.impl_ty).m_data, Infer, e2,
- //context.possible_equate_type_from(e2.index, *pe.type);
- //context.possible_equate_type_to(e2.index, *pe.type);
- return false;
- )
- else {
- context.equate_types(sp, *pe.type, v.impl_ty);
- return true;
- }
- #endif
+ // 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.
+ 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");
+ const auto& src_ty = context.get_type(v.impl_ty);
+ const auto& dst_ty = context.get_type(v.params.m_types[0]);
+
+ // - If the two types are equal (for unsizing purposes) then equate them and delete this rule
+ if( context.m_ivars.types_equal( src_ty, dst_ty ) ) {
+ // A type cannot unsize to itself, but CoerceUnsize code leads to these requirements when coercion points chain.
+ return true;
+ }
+ // > TODO: Detect when the unsize cannot happen and equate the types.
+ // - If either is an ivar, add the other as a possibility
+ TU_IFLET( ::HIR::TypeRef::Data, src_ty.m_data, Infer, se,
+ // TODO: Update for InferClass::Diverge ?
+ if( se.ty_class != ::HIR::InferClass::None ) {
+ context.equate_types(sp, dst_ty, src_ty);
+ }
+ else {
+ TU_IFLET(::HIR::TypeRef::Data, dst_ty.m_data, Infer, de,
+ context.possible_equate_type_to(se.index, dst_ty);
+ context.possible_equate_type_from(de.index, src_ty);
+ )
+ else {
+ context.possible_equate_type_to(se.index, dst_ty);
}
- )
+ }
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, dst_ty.m_data, Infer, de,
+ // TODO: Update for InferClass::Diverge ?
+ if( de.ty_class != ::HIR::InferClass::None ) {
+ context.equate_types(sp, dst_ty, src_ty);
+ }
+ else {
+ context.possible_equate_type_from(de.index, src_ty);
+ }
+ )
+ else {
+ // No equivalence added
}
- )
- #endif
+ // - Fall through and search for the impl
+ }
+ if( v.trait == context.m_crate.get_lang_item_path(sp, "coerce_unsized") )
+ {
+ 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]);
+ if( !src_ty.m_data.is_Infer() && !dst_ty.m_data.is_Infer() )
+ {
+ // 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");
+ context.equate_types(sp, dst_ty, src_ty);
+ return true;
+ }
+ DEBUG("Found at least one impl of CoerceUnsized, running expensive code");
+ }
+ }
// Locate applicable trait impl
unsigned int count = 0;
DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ ImplRef best_impl;
bool found = context.m_resolve.find_trait_impls(sp, v.trait, v.params, v.impl_ty,
[&](auto impl, auto cmp) {
DEBUG("[check_associated] Found cmp=" << cmp << " " << impl);
@@ -3873,13 +3923,14 @@ namespace {
return true;
}
else {
+ DEBUG("- (possible) " << impl);
+
if( possible_impl_ty == ::HIR::TypeRef() ) {
possible_impl_ty = impl.get_impl_type();
possible_params = impl.get_trait_params();
+ best_impl = mv$(impl);
}
- DEBUG("- (possible) " << impl);
-
return false;
}
});
@@ -3894,6 +3945,7 @@ namespace {
// No applicable impl
// - TODO: This should really only fire when there isn't an impl. But it currently fires when _
DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ //bool is_known = !context.get_type(v.impl_ty).m_data.is_Infer();
bool is_known = !context.m_ivars.type_contains_ivars(v.impl_ty);
for(const auto& t : v.params.m_types)
is_known &= !context.m_ivars.type_contains_ivars(t);
@@ -3914,6 +3966,31 @@ namespace {
for( unsigned int i = 0; i < possible_params.m_types.size(); i ++ ) {
context.equate_types(sp, v.params.m_types[i], possible_params.m_types[i]);
}
+ // TODO: Obtain the bounds required for this impl and add those as trait bounds to check/equate
+ TU_IFLET( ImplRef::Data, best_impl.m_data, TraitImpl, e,
+ assert(e.impl);
+ for(const auto& bound : e.impl->m_params.m_bounds )
+ {
+ TU_MATCH_DEF(::HIR::GenericBound, (bound), (be),
+ (
+ ),
+ (TraitBound,
+ DEBUG("New bound (pre-mono) " << bound);
+ auto b_ty_mono = monomorphise_type_with(sp, be.type, best_impl.get_cb_monomorph_traitimpl(sp));
+ auto b_tp_mono = monomorphise_traitpath_with(sp, be.trait, best_impl.get_cb_monomorph_traitimpl(sp), true);
+ DEBUG("- " << b_ty_mono << " : " << b_tp_mono);
+ if( b_tp_mono.m_type_bounds.size() > 0 )
+ {
+ TODO(sp, "Insert new bound " << b_ty_mono << " : " << b_tp_mono);
+ }
+ else
+ {
+ context.equate_types_assoc(sp, ::HIR::TypeRef(), b_tp_mono.m_path.m_path, mv$(b_tp_mono.m_path.m_params.m_types), b_ty_mono, "");
+ }
+ )
+ )
+ }
+ )
return true;
}
else {
@@ -4202,10 +4279,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
// 3. Check associated type rules
DEBUG("--- Associated types");
- //for(auto it = context.link_assoc.begin(); it != context.link_assoc.end(); ) {
- // const auto& rule = *it;
- for(unsigned int i = 0; i < context.link_assoc.size(); ) {
- auto& rule = context.link_assoc[i];
+ for(unsigned int i = 0; i < context.link_assoc.size(); ) {
+ // - Move out (and back in later) to avoid holding a bad pointer if the list is updated
+ auto rule = mv$(context.link_assoc[i]);
DEBUG("- " << rule);
for( auto& ty : rule.params.m_types ) {
@@ -4219,10 +4295,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
if( check_associated(context, rule) ) {
DEBUG("- Consumed associated type rule - " << rule);
context.link_assoc.erase( context.link_assoc.begin() + i );
- //it = context.link_assoc.erase(it);
}
else {
- //++ it;
+ context.link_assoc[i] = mv$(rule);
i ++;
}
}
diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp
index 076782bf..7b3dfe60 100644
--- a/src/hir_typeck/impl_ref.cpp
+++ b/src/hir_typeck/impl_ref.cpp
@@ -66,26 +66,24 @@ bool ImplRef::type_is_specialisable(const char* name) const
throw "";
}
-namespace {
- // Returns a closure to monomorphise including placeholders (if present)
- ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> get_cb_monomorph_traitimpl(const Span& sp, const ImplRef& ir)
- {
- const auto& e = ir.m_data.as_TraitImpl();
- return [&e,&ir,&sp](const auto& gt)->const auto& {
- const auto& ge = gt.m_data.as_Generic();
- assert(ge.binding < 256);
- assert(ge.binding < e.params.size());
- if( e.params[ge.binding] ) {
- return *e.params[ge.binding];
- }
- else if( e.params_ph.size() && e.params_ph[ge.binding] != ::HIR::TypeRef() ) {
- return e.params_ph[ge.binding];
- }
- else {
- BUG(sp, "Param #" << ge.binding << " " << ge.name << " isn't constrained for " << ir);
- }
- };
- }
+// Returns a closure to monomorphise including placeholders (if present)
+::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> ImplRef::get_cb_monomorph_traitimpl(const Span& sp) const
+{
+ const auto& e = this->m_data.as_TraitImpl();
+ return [this,&e,&sp](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ assert(ge.binding < 256);
+ assert(ge.binding < e.params.size());
+ if( e.params[ge.binding] ) {
+ return *e.params[ge.binding];
+ }
+ else if( e.params_ph.size() && e.params_ph[ge.binding] != ::HIR::TypeRef() ) {
+ return e.params_ph[ge.binding];
+ }
+ else {
+ BUG(sp, "Param #" << ge.binding << " " << ge.name << " isn't constrained for " << *this);
+ }
+ };
}
::HIR::TypeRef ImplRef::get_impl_type() const
@@ -96,7 +94,7 @@ namespace {
if( e.impl == nullptr ) {
BUG(Span(), "nullptr");
}
- return monomorphise_type_with(sp, e.impl->m_type, get_cb_monomorph_traitimpl(sp, *this));
+ return monomorphise_type_with(sp, e.impl->m_type, this->get_cb_monomorph_traitimpl(sp));
),
(BoundedPtr,
return e.type->clone();
@@ -116,7 +114,7 @@ namespace {
BUG(Span(), "nullptr");
}
- return monomorphise_path_params_with(sp, e.impl->m_trait_args, get_cb_monomorph_traitimpl(sp, *this), true);
+ return monomorphise_path_params_with(sp, e.impl->m_trait_args, this->get_cb_monomorph_traitimpl(sp), true);
),
(BoundedPtr,
return e.trait_args->clone();
@@ -137,7 +135,7 @@ namespace {
}
if( idx >= e.impl->m_trait_args.m_types.size() )
return ::HIR::TypeRef();
- return monomorphise_type_with(sp, e.impl->m_trait_args.m_types[idx], get_cb_monomorph_traitimpl(sp, *this), true);
+ return monomorphise_type_with(sp, e.impl->m_trait_args.m_types[idx], this->get_cb_monomorph_traitimpl(sp), true);
),
(BoundedPtr,
if( idx >= e.trait_args->m_types.size() )
@@ -167,7 +165,7 @@ namespace {
return ::HIR::TypeRef();
const ::HIR::TypeRef& tpl_ty = it->second.data;
if( monomorphise_type_needed(tpl_ty) ) {
- return monomorphise_type_with(sp, tpl_ty, get_cb_monomorph_traitimpl(sp, *this));
+ return monomorphise_type_with(sp, tpl_ty, this->get_cb_monomorph_traitimpl(sp));
}
else {
return tpl_ty.clone();
diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp
index 12d84045..910f445f 100644
--- a/src/hir_typeck/impl_ref.hpp
+++ b/src/hir_typeck/impl_ref.hpp
@@ -51,6 +51,9 @@ struct ImplRef
bool more_specific_than(const ImplRef& other) const;
+ /// 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;
+
::HIR::TypeRef get_impl_type() const;
::HIR::PathParams get_trait_params() const;