diff options
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 124 |
1 files changed, 104 insertions, 20 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 1f43a89c..6d101cbd 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -94,6 +94,7 @@ struct Context struct IVarPossible { + bool force_disable = false; bool force_no_to = false; bool force_no_from = false; // Target types for coercion/unsizing (these types are known to exist in the function) @@ -203,6 +204,7 @@ struct Context equate_types_shadow(sp, l, false); } void equate_types_shadow(const Span& sp, const ::HIR::TypeRef& ty, bool is_to); + void equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty); /// Possible type that this ivar can coerce to void possible_equate_type_coerce_to(unsigned int ivar_index, const ::HIR::TypeRef& t) { @@ -235,6 +237,7 @@ struct Context void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow); void possible_equate_type_disable(unsigned int ivar_index, bool is_to); + void possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index); // - Add a pattern binding (forcing the type to match) void handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); @@ -4894,6 +4897,46 @@ void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool ) ) } +void Context::equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty) +{ + // TODO: Would like to use visit_ty_with in a way that can be told to not recurse (for non-Generic paths) + TU_MATCH_DEF(::HIR::TypeRef::Data, (this->get_type(ty).m_data), (e), + ( + // TODO: Shadow sub-types too + ), + (Path, + TU_MATCH_DEF( ::HIR::Path::Data, (e.path.m_data), (pe), + ( + ), + (Generic, + for(const auto& sty : pe.m_params.m_types) + this->equate_types_shadow_strong(sp, sty); + ) + ) + ), + (Tuple, + for(const auto& sty : e) + this->equate_types_shadow_strong(sp, sty); + ), + (Borrow, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Array, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Slice, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Closure, + for(const auto& aty : e.m_arg_types) + this->equate_types_shadow_strong(sp, aty); + this->equate_types_shadow_strong(sp, *e.m_rettype); + ), + (Infer, + this->possible_equate_type_disable_strong(sp, e.index); + ) + ) +} void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::SimplePath& trait, ::HIR::PathParams pp, const ::HIR::TypeRef& impl_ty, const char *name, bool is_op) { for(const auto& a : this->link_assoc) @@ -5095,6 +5138,21 @@ void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) ent.force_no_from = true; } } +void Context::possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index) +{ + DEBUG(ivar_index << " = ??"); + { + ::HIR::TypeRef ty_l; + ty_l.m_data.as_Infer().index = ivar_index; + ASSERT_BUG(sp, m_ivars.get_type(ty_l).m_data.is_Infer(), "possible_equate_type_disable_strong on known ivar"); + } + + if( ivar_index >= possible_ivar_vals.size() ) { + possible_ivar_vals.resize( ivar_index + 1 ); + } + auto& ent = possible_ivar_vals[ivar_index]; + ent.force_disable = true; +} void Context::add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type) { DEBUG("(" << index << " " << name << " : " << type << ")"); @@ -6102,10 +6160,10 @@ namespace { } else if( src.m_data.is_Closure() ) { + const auto& se = src.m_data.as_Closure(); if( dst.m_data.is_Function() ) { const auto& de = dst.m_data.as_Function(); - const auto& se = src.m_data.as_Closure(); auto& node_ptr = *node_ptr_ptr; auto span = node_ptr->span(); if( de.m_abi != ABI_RUST ) { @@ -6124,6 +6182,11 @@ namespace { } else if( const auto* dep = dst.m_data.opt_Infer() ) { + // Prevent inferrence of argument/return types + for(const auto& at : se.m_arg_types) + context.equate_types_to_shadow(sp, at); + context.equate_types_to_shadow(sp, *se.m_rettype); + // Add as a possiblity context.possible_equate_type_coerce_from(dep->index, src); return CoerceResult::Unknown; } @@ -6231,7 +6294,7 @@ namespace { // - This generates an exact equation. if( v.left_ty != ::HIR::TypeRef() ) { - context.equate_types_from_shadow(sp, v.left_ty); + context.equate_types_shadow_strong(sp, v.left_ty); } // Locate applicable trait impl @@ -6522,13 +6585,16 @@ namespace { if( bound.name != "" ) { auto aty = impl.get_type(bound.name.c_str()); + // The associated type is not present, what does that mean? if( aty == ::HIR::TypeRef() ) { + DEBUG("[check_ivar_poss__fails_bounds] No ATY for " << bound.name << " in impl"); // A possible match was found, so don't delete just yet bound_failed = false; // - Return false to keep searching return false; } else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) { + DEBUG("[check_ivar_poss__fails_bounds] ATY " << context.m_ivars.fmt_type(aty) << " != left " << context.m_ivars.fmt_type(bound.left_ty)); bound_failed = true; // - Bail instantly return true; @@ -6585,11 +6651,16 @@ namespace { static Span _span; const auto& sp = _span; - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + if( ivar_ent.force_disable ) { DEBUG(i << ": forced unknown"); return false; } + if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + { + DEBUG(i << ": coercion blocked"); + return false; + } ::HIR::TypeRef ty_l_ivar; ty_l_ivar.m_data.as_Infer().index = i; @@ -7199,9 +7270,9 @@ namespace { { // TODO: Search know possibilties and check if they satisfy the bounds for this ivar DEBUG("Options: " << ivar_ent.bounded); - unsigned int n_good = 0; unsigned int n_good_ints = 0; - const ::HIR::TypeRef* only_good = nullptr; + ::std::vector<const ::HIR::TypeRef*> good_types; + good_types.reserve(ivar_ent.bounded.size()); for(const auto& new_ty : ivar_ent.bounded) { DEBUG("- Test " << new_ty << " against current rules"); @@ -7210,9 +7281,7 @@ namespace { } else { - n_good ++; - if( !only_good ) - only_good = &new_ty; + good_types.push_back(&new_ty); if( new_ty.m_data.is_Primitive() ) n_good_ints ++; @@ -7220,21 +7289,36 @@ namespace { DEBUG("> " << new_ty << " feasible"); } } + DEBUG(good_types.size() << " valid options (" << n_good_ints << " primitives)"); // Picks the first if in fallback mode (which is signalled by `honour_disable` being false) // - This handles the case where there's multiple valid options (needed for libcompiler_builtins) // TODO: Only pick any if all options are the same class (or just all are integers) - if( (honour_disable ? n_good == 1 : n_good > 0) ) - //if( n_good == 1 || (honour_disable ? false : n_good == n_good_ints) ) + if( good_types.empty() ) + { + + } + else if( good_types.size() == 1 ) { - if( honour_disable ) - DEBUG("Only " << *only_good << " fits current bound sets"); - else - DEBUG("Picking " << *only_good << " as first of " << n_good << " options"); // Since it's the only possibility, choose it? - context.equate_types(sp, ty_l, *only_good); + DEBUG("Only " << *good_types.front() << " fits current bound sets"); + context.equate_types(sp, ty_l, *good_types.front()); return true; } - DEBUG(n_good << " valid options (" << n_good_ints << " primitives)"); + else if( good_types.size() > 0 && !honour_disable ) + { + auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); }; + // NOTE: We want to select from sets of primitives and generics (which can be interchangable) + if( ::std::all_of(good_types.begin(), good_types.end(), typ_is_borrow) == ::std::any_of(good_types.begin(), good_types.end(), typ_is_borrow) ) + { + DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options"); + context.equate_types(sp, ty_l, *good_types.front()); + return true; + } + else + { + // Mix of borrows with non-borrows + } + } } return false; @@ -7407,8 +7491,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 - // NOTE: Ordering is a hack for libgit2 - for(unsigned int 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; @@ -7517,8 +7601,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { // Check the possible equations DEBUG("--- IVar possibilities (fallback)"); - // NOTE: Ordering is a hack for libgit2 - for(unsigned int 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], /*honour_disable=*/false) ) { # if 1 |