diff options
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 157 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 4 |
2 files changed, 156 insertions, 5 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 66a99a1c..9b1b35b5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -155,8 +155,9 @@ struct Context Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params): m_crate(crate), - m_resolve(m_ivars, crate, impl_params, item_params), - m_lang_Box( crate.get_lang_item_path_opt("owned_box") ) + m_resolve(m_ivars, crate, impl_params, item_params) + ,next_rule_idx( 0 ) + ,m_lang_Box( crate.get_lang_item_path_opt("owned_box") ) { } @@ -6908,6 +6909,22 @@ namespace { } DEBUG("possible_tys = " << possible_tys); + if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge ) + { + // There's a coercion (not an unsizing) AND there's no sources + // - This ensures that the ! is directly as a value, and not as a generic param or behind a pointer + if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.is_pointer; }) + && ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.can_deref; }) + ) + { + // There are no source possibilities, this has to be a `!` + DEBUG("- Diverge with no source types, force setting to !"); + DEBUG("Set IVar " << i << " = !"); + context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge(); + return true; + } + } + // Filter out ivars // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes) size_t n_ivars; @@ -6915,6 +6932,7 @@ namespace { size_t n_dst_ivars; { auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent) { + // TODO: Should this remove Unbound associated types too? return ent.ty->m_data.is_Infer(); }); n_ivars = possible_tys.end() - new_end; @@ -6935,6 +6953,138 @@ namespace { } (void)n_ivars; + // === If there's no source ivars, find the least permissive source === + // - If this source can't be unsized (e.g. in `&_, &str`, `&str` is the least permissive, and can't be + // coerced without a `*const _` in the list), then equate to that + // 1. Find the most accepting pointer type (if there is at least one coercion source) + // 2. Look for an option that uses that pointer type, and contains an unsized type (that isn't a trait + // object with markers) + // 3. Assign to that known most-permissive option + // Do the oposite for the destination types (least permissive pointer, pick any Sized type) + if( n_src_ivars == 0 || fallback_ty == IvarPossFallbackType::Assume ) + { + static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { + //::HIR::TypeRef::Data::TAG_Generic, + ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic? + ::HIR::TypeRef::Data::TAG_Borrow, + ::HIR::TypeRef::Data::TAG_Pointer, + }; + struct H { + static Ordering ord_accepting_ptr(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) + { + // Ordering in increasing acceptiveness: + // - Paths, Borrows, Raw Pointers + if( ty_l.m_data.tag() != ty_r.m_data.tag() ) + { + const auto* tag_ordering_end = tag_ordering+sizeof(tag_ordering)/sizeof(tag_ordering[0]); + auto it_l = ::std::find(tag_ordering, tag_ordering_end, ty_l.m_data.tag()); + auto it_r = ::std::find(tag_ordering, tag_ordering_end, ty_r.m_data.tag()); + if( it_l == tag_ordering_end || it_r == tag_ordering_end ) { + // Huh? + return OrdEqual; + } + if( it_l < it_r ) + return OrdLess; + else if( it_l > it_r ) + return OrdGreater; + else + throw "Impossible"; + } + + switch(ty_l.m_data.tag()) + { + case ::HIR::TypeRef::Data::TAG_Borrow: + // Reverse order - Shared is numerically lower than Unique, but is MORE accepting + return ::ord( static_cast<int>(ty_r.m_data.as_Borrow().type), static_cast<int>(ty_l.m_data.as_Borrow().type) ); + case ::HIR::TypeRef::Data::TAG_Pointer: + // Reverse order - Shared is numerically lower than Unique, but is MORE accepting + return ::ord( static_cast<int>(ty_r.m_data.as_Pointer().type), static_cast<int>(ty_l.m_data.as_Pointer().type) ); + case ::HIR::TypeRef::Data::TAG_Path: + return OrdEqual; + case ::HIR::TypeRef::Data::TAG_Generic: + return OrdEqual; + default: + // Technically a bug/error + return OrdEqual; + } + } + + static const ::HIR::TypeRef* match_and_extract_ptr_ty(const ::HIR::TypeRef& ptr_tpl, const ::HIR::TypeRef& ty) + { + if( ty.m_data.tag() != ptr_tpl.m_data.tag() ) + return nullptr; + TU_MATCH_HDRA( (ty.m_data), { ) + TU_ARMA(Borrow, te) { + if( te.type == ptr_tpl.m_data.as_Borrow().type ) { + return &*te.inner; + } + } + TU_ARMA(Pointer, te) { + if( te.type == ptr_tpl.m_data.as_Pointer().type ) { + return &*te.inner; + } + } + TU_ARMA(Path, te) { + if( te.binding == ptr_tpl.m_data.as_Path().binding ) { + // TODO: Get inner + } + } break; + default: + break; + } + return nullptr; + } + }; + const ::HIR::TypeRef* ptr_ty = nullptr; + if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [&](const auto& ent){ return ent.can_deref && ent.is_pointer; }) ) + { + for(const auto& ent : possible_tys) + { + if( !ent.can_deref ) + continue; + + if( ptr_ty == nullptr ) + { + ptr_ty = ent.ty; + } + else if( H::ord_accepting_ptr(*ent.ty, *ptr_ty) == OrdGreater ) + { + ptr_ty = ent.ty; + } + else + { + } + } + } + + for(const auto& ent : possible_tys) + { + // Sources only + if( ! ent.can_deref ) + continue ; + // Must match `ptr_ty`'s outer pointer + const ::HIR::TypeRef* inner_ty = (ptr_ty ? H::match_and_extract_ptr_ty(*ptr_ty, *ent.ty) : ent.ty); + if( !inner_ty ) + continue; + + bool is_max_accepting = false; + if( inner_ty->m_data.is_Slice() ) { + is_max_accepting = true; + } + else if( TU_TEST1(inner_ty->m_data, Primitive, == ::HIR::CoreType::Str) ) { + is_max_accepting = true; + } + else { + } + if( is_max_accepting ) + { + DEBUG("Most accepting pointer class, and most permissive inner type - " << *ent.ty); + context.equate_types(sp, ty_l, *ent.ty); + return true; + } + } + } + struct TypeRestrictiveOrdering { static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r) { @@ -7609,7 +7759,8 @@ namespace { DEBUG("possible_tys = " << possible_tys); // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it - if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) + //if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) + if( possible_tys.size() == 1 && n_ivars == 0 ) { const auto& new_ty = *possible_tys[0].ty; DEBUG("Only " << new_ty << " is an option"); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index cb26f0be..529d2727 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -619,9 +619,9 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) } #if 1 - TU_IFLET(::HIR::TypeRef::Data, type.m_data, Diverge, e, + if( type.m_data.is_Diverge() ) { root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge; - ) + } else #endif root_ivar.type = box$( mv$(type) ); |