diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 88 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 86 |
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; } |