summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-09-30 21:12:20 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-09-30 21:12:20 +0800
commiteb8c70a071a91ac8f2dd2710206e7d46c4e3bd4d (patch)
tree86a61b8f961b93259d0c7f9020a95f7e2a1b2524
parent47b61b93c2ac841fe44d6cc8ca8fd91bd00b0e10 (diff)
downloadmrust-eb8c70a071a91ac8f2dd2710206e7d46c4e3bd4d.tar.gz
HIR Typecheck - Working cargo 1.19
-rw-r--r--src/hir_typeck/expr_cs.cpp88
-rw-r--r--src/hir_typeck/helpers.cpp86
2 files changed, 150 insertions, 24 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index af076092..3d2ba634 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -576,6 +576,22 @@ namespace {
return true;
}
+ class ExprVisitor_AddIvars:
+ public HIR::ExprVisitorDef
+ {
+ Context& context;
+ public:
+ ExprVisitor_AddIvars(Context& context):
+ context(context)
+ {
+ }
+
+ void visit_type(::HIR::TypeRef& ty)
+ {
+ this->context.add_ivars(ty);
+ }
+ };
+
// -----------------------------------------------------------------------
// Enumeration visitor
//
@@ -2468,6 +2484,8 @@ namespace {
{
// Can't do anything, the place is still unknown
DEBUG("Place unknown, wait");
+ //this->context.equate_types_to_shadow(sp, placer_ty);
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
@@ -2497,6 +2515,7 @@ namespace {
auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str );
this->context.possible_equate_type_coerce_from( exp_ty.m_data.as_Infer().index, boxed_ty );
}
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
// Assert that the expected result is a Path::Generic type.
@@ -6209,15 +6228,23 @@ namespace {
// - Recurse/unsize inner value
if( src.m_data.is_Infer() && TU_TEST2(dst.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_src = H::make_pruned(context, dst);
context.equate_types(sp, src, new_src);
+#else
+ context.possible_equate_type_coerce_to(src.m_data.as_Infer().index, dst);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
if( dst.m_data.is_Infer() && TU_TEST2(src.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_dst = H::make_pruned(context, src);
context.equate_types(sp, dst, new_dst);
+#else
+ context.possible_equate_type_coerce_from(dst.m_data.as_Infer().index, src);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
@@ -7087,6 +7114,8 @@ namespace {
}
bool is_source() const { return this->can_deref; }
+ bool is_dest() const { return !this->can_deref; }
+ static bool is_dest_s(const PossibleType& self) { return self.is_dest(); }
};
bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false);
@@ -7189,6 +7218,18 @@ namespace {
}
}
+ // TODO: Single destination, and all sources are coerce-able
+ // - Pick the single destination
+ #if 0
+ if( !ivar_ent.force_no_to && ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s) == 1 )
+ {
+ auto ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s);
+ DEBUG("One destination, setting to " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ #endif
+
// Filter out ivars
// - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes)
size_t n_ivars;
@@ -7593,7 +7634,8 @@ namespace {
}
}
// TODO: Unsized types? Don't pick an unsized if coercions are present?
- if( num_distinct > 1 && dest_type )
+ // TODO: If in a fallback mode, then don't require >1 (just require dest_type)
+ if( (num_distinct > 1 || fallback_ty == IvarPossFallbackType::Assume) && dest_type )
{
DEBUG("- Most-restrictive destination " << *dest_type);
context.equate_types(sp, ty_l, *dest_type);
@@ -8305,6 +8347,13 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
return false;
});
+ if(true)
+ {
+ ExprVisitor_AddIvars visitor(context);
+ context.add_ivars(root_ptr->m_res_type);
+ root_ptr->visit(visitor);
+ }
+
ExprVisitor_Enum visitor(context, ms.m_traits, result_type);
context.add_ivars(root_ptr->m_res_type);
root_ptr->visit(visitor);
@@ -8433,8 +8482,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
// Check the possible equations
DEBUG("--- IVar possibilities");
// TODO: De-duplicate this with the block ~80 lines below
- for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
- //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i]) ) {
static Span sp;
@@ -8489,7 +8538,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
auto& src_ty = (**ent.right_node_ptr).m_res_type;
//src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
- DEBUG("- Equate coercion " << ent.left_ty << " := " << src_ty);
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
context.equate_types(sp, ent.left_ty, src_ty);
}
@@ -8500,22 +8549,41 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
// Check the possible equations
DEBUG("--- IVar possibilities (fallback 1)");
- for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
- //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::Assume) ) {
break;
}
}
}
+#if 0
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
+ {
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
+
+ context.equate_types(sp, ent.left_ty, src_ty);
+ }
+ }
+#endif
// If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag
#if 1
if( !context.m_ivars.peek_changed() )
{
// Check the possible equations
DEBUG("--- IVar possibilities (fallback)");
- for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
- //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::IgnoreWeakDisable) ) {
# if 1
@@ -8611,8 +8679,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
// Check the possible equations
DEBUG("--- IVar possibilities (final fallback)");
- for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
- //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::FinalOption) ) {
break;
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index c2e95fd6..08e817de 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -558,30 +558,38 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
DEBUG("set_ivar_to(" << slot << " { " << *root_ivar.type << " }, " << type << ")");
// If the left type was '_', alias the right to it
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Infer, l_e,
- assert( l_e.index != slot );
- DEBUG("Set IVar " << slot << " = @" << l_e.index);
-
- if( l_e.ty_class != ::HIR::InferClass::None ) {
+ if( const auto* l_e = type.m_data.opt_Infer() )
+ {
+ assert( l_e->index != slot );
+ if( l_e->ty_class != ::HIR::InferClass::None ) {
TU_MATCH_DEF(::HIR::TypeRef::Data, (root_ivar.type->m_data), (e),
(
ERROR(sp, E0000, "Type unificiation of literal with invalid type - " << *root_ivar.type);
),
(Primitive,
- check_type_class_primitive(sp, type, l_e.ty_class, e);
+ check_type_class_primitive(sp, type, l_e->ty_class, e);
),
(Infer,
// Check for right having a ty_class
- if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e.ty_class ) {
+ if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e->ty_class ) {
ERROR(sp, E0000, "Unifying types with mismatching literal classes - " << type << " := " << *root_ivar.type);
}
)
)
}
- root_ivar.alias = l_e.index;
+ #if 1
+ // Alias `l_e.index` to this slot
+ DEBUG("Set IVar " << l_e->index << " = @" << slot);
+ auto& r_ivar = this->get_pointed_ivar(l_e->index);
+ r_ivar.alias = slot;
+ r_ivar.type.reset();
+ #else
+ DEBUG("Set IVar " << slot << " = @" << l_e->index);
+ root_ivar.alias = l_e->index;
root_ivar.type.reset();
- )
+ #endif
+ }
else if( *root_ivar.type == type ) {
return ;
}
@@ -2869,6 +2877,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
auto i = idx % 256;
ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned - " << *impl_params[i] << " vs " << ty);
auto& ph = placeholders[i];
+ // TODO: Only want to do this if ... what?
+ // - Problem: This can poison the output if the result was fuzzy
+ // - E.g. `Q: Borrow<V>` can equate Q and V
if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
DEBUG("[ftic_check_params:cb_match] Bind placeholder " << i << " to " << ty);
ph = ty.clone();
@@ -2906,6 +2917,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
return *impl_params[ge.binding];
};
+ //::std::vector<::HIR::TypeRef> saved_ph;
+ //for(const auto& t : placeholders)
+ // saved_ph.push_back(t.clone());
// Check bounds for this impl
// - If a bound fails, then this can't be a valid impl
@@ -2917,6 +2931,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
(TypeLifetime,
),
(TraitBound,
+
DEBUG("Check bound " << be.type << " : " << be.trait);
auto real_type = monomorphise_type_with(sp, be.type, monomorph, false);
auto real_trait = monomorphise_traitpath_with(sp, be.trait, monomorph, false);
@@ -2940,8 +2955,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bounded type is an ivar, assuming fuzzy match");
found_fuzzy_match = true;
}
+ // TODO: Save the placeholder state and restore if the result was Fuzzy
+ ::std::vector<::HIR::TypeRef> saved_ph;
+ for(const auto& t : placeholders)
+ saved_ph.push_back(t.clone());
+ ::std::vector<::HIR::TypeRef> fuzzy_ph;
+ unsigned num_fuzzy = 0;
// TODO: Pass the `match_test_generics` callback? Or another one that handles the impl placeholders.
auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](auto impl, auto impl_cmp) {
+ // TODO: Save and restore placeholders if this isn't a full match
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", impl = " << impl);
auto cmp = impl_cmp;
if( cmp == ::HIR::Compare::Fuzzy )
@@ -2984,22 +3006,41 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
{
case ::HIR::Compare::Equal:
DEBUG("Equal");
- continue;
+ break;
case ::HIR::Compare::Unequal:
DEBUG("Assoc `" << assoc_bound.first << "` didn't match - " << ty << " != " << assoc_bound.second);
- return false;
+ cmp = ::HIR::Compare::Unequal;
+ break;
case ::HIR::Compare::Fuzzy:
// TODO: When a fuzzy match is encountered on a conditional bound, returning `false` can lead to an false negative (and a compile error)
// BUT, returning `true` could lead to it being selected. (Is this a problem, should a later validation pass check?)
DEBUG("[ftic_check_params] Fuzzy match assoc bound between " << ty << " and " << assoc_bound.second);
cmp = ::HIR::Compare::Fuzzy;
- continue ;
+ break ;
}
+ if( cmp == ::HIR::Compare::Unequal )
+ break;
}
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", cmp = " << cmp);
- if( cmp == ::HIR::Compare::Fuzzy ) {
- found_fuzzy_match = true;
+ if( cmp == ::HIR::Compare::Fuzzy )
+ {
+ found_fuzzy_match |= true;
+ num_fuzzy += 1;
+ if( num_fuzzy )
+ {
+ fuzzy_ph = ::std::move(placeholders);
+ placeholders.resize(fuzzy_ph.size());
+ }
+ }
+ if( cmp != ::HIR::Compare::Equal )
+ {
+ // Restore placeholders
+ // - Maybe save the results for later?
+ DEBUG("[ftic_check_params] Restore placeholders: " << saved_ph);
+ DEBUG("[ftic_check_params] OVERWRITTEN placeholders: " << placeholders);
+ for(size_t i = 0; i < placeholders.size(); i ++)
+ placeholders[i] = saved_ph[i].clone();
}
// If the match isn't a concrete equal, return false (to keep searching)
return (cmp == ::HIR::Compare::Equal);
@@ -3009,6 +3050,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
else if( found_fuzzy_match ) {
DEBUG("- Bound " << real_type << " : " << real_trait_path << " fuzzed");
+ if( num_fuzzy == 1 )
+ {
+ DEBUG("Use placeholders " << fuzzy_ph);
+ placeholders = ::std::move(fuzzy_ph);
+ }
+ else
+ {
+ DEBUG("TODO: Multiple fuzzy matches, which placeholder set to use?");
+ }
match = ::HIR::Compare::Fuzzy;
}
else if( TU_TEST1(real_type.m_data, Infer, .ty_class == ::HIR::InferClass::None) ) {
@@ -3023,6 +3073,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bound " << real_type << " : " << real_trait_path << " failed");
return ::HIR::Compare::Unequal;
}
+
+ //if( !rv ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
),
(TypeEquality,
TODO(sp, "Check bound " << be.type << " = " << be.other_type);
@@ -3047,6 +3101,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
}
+ //if( match == ::HIR::Compare::Fuzzy ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
+
return match;
}