From 444f4915d27837ac3d6515f081519f4fe2e07eed Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 24 Apr 2019 12:21:20 +0800 Subject: Typecheck Expressions - Add an unsize target instead of hard equality in match ergonoics --- src/hir/hir_ops.cpp | 8 ++- src/hir_typeck/expr_cs.cpp | 172 ++++++++++++++++++++++++++++----------------- src/hir_typeck/helpers.cpp | 2 + 3 files changed, 113 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index 4b35a0f0..b09dbdf7 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -215,9 +215,9 @@ namespace { namespace { bool is_unbounded_infer(const ::HIR::TypeRef& type) { - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e, - return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge; - ) + if( const auto* e = type.m_data.opt_Infer() ) { + return e->ty_class == ::HIR::InferClass::None || e->ty_class == ::HIR::InferClass::Diverge; + } else { return false; } @@ -229,6 +229,8 @@ bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_reso // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway // TODO: For `Unbound`, it could be valid, if the target is a generic. // - Pure infer could also be useful (for knowing if there's any other potential impls) + + // TODO: Allow unbounded types iff there's some non-unbounded parameters? if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { return false; } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 7f910415..762adf5a 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2324,6 +2324,9 @@ namespace { do { const auto& ty = this->context.get_type(*current_ty); DEBUG("(Index): (: " << ty << ")[: " << trait_pp.m_types[0] << "]"); + if( ty.m_data.is_Infer() ) { + return ; + } ::HIR::TypeRef possible_index_type; ::HIR::TypeRef possible_res_type; @@ -3951,6 +3954,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T ::HIR::PatternBinding::Type m_outer_mode; mutable ::std::vector<::HIR::TypeRef> m_temp_ivars; + mutable ::HIR::TypeRef m_possible_type; MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move): sp(mv$(sp)), m_outer_ty(mv$(outer)), @@ -3983,6 +3987,78 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } return true; } + const ::HIR::TypeRef& get_possible_type(Context& context, ::HIR::Pattern& pattern) const + { + if( m_possible_type == ::HIR::TypeRef() ) + { + ::HIR::TypeRef possible_type; + // Get a potential type from the pattern, and set as a possibility. + // - Note, this is only if no derefs were applied + TU_MATCH_HDR( (pattern.m_data), { ) + TU_ARM(pattern.m_data, Any, pe) { + // No type information. + } + TU_ARM(pattern.m_data, Value, pe) { + // TODO: Get type info + } + TU_ARM(pattern.m_data, Range, pe) { + // TODO: Get type info (same as Value) + } + TU_ARM(pattern.m_data, Box, pe) { + // TODO: Get type info (Box<_>) + } + TU_ARM(pattern.m_data, Ref, pe) { + BUG(sp, "Match ergonomics - & pattern"); + } + TU_ARM(pattern.m_data, Tuple, e) { + // Get type info `(T, U, ...)` + if( m_temp_ivars.size() != e.sub_patterns.size() ) { + for(size_t i = 0; i < e.sub_patterns.size(); i ++) + m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() ); + } + decltype(m_temp_ivars) tuple; + for(const auto& ty : m_temp_ivars) + tuple.push_back(ty.clone()); + possible_type = ::HIR::TypeRef( ::std::move(tuple) ); + } + TU_ARM(pattern.m_data, SplitTuple, pe) { + // Can't get type information, tuple size is unkown + } + TU_ARM(pattern.m_data, Slice, e) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, SplitSlice, pe) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, StructValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, StructTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, Struct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, EnumValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumStruct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + } + m_possible_type = ::std::move(possible_type); + } + return m_possible_type; + } bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode, bool is_fallback) const { TRACE_FUNCTION_F(pattern << " : " << type); @@ -4046,76 +4122,30 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } } - if( n_deref == 0 && is_fallback ) + // If there's no dereferences done, then + if( n_deref == 0 ) { - ::HIR::TypeRef possible_type; - // Get a potential type from the pattern, and set as a possibility. - // - Note, this is only if no derefs were applied - TU_MATCH_HDR( (pattern.m_data), { ) - TU_ARM(pattern.m_data, Any, pe) { - // No type information. - } - TU_ARM(pattern.m_data, Value, pe) { - // TODO: Get type info - } - TU_ARM(pattern.m_data, Range, pe) { - // TODO: Get type info (same as Value) - } - TU_ARM(pattern.m_data, Box, pe) { - // TODO: Get type info (Box<_>) - } - TU_ARM(pattern.m_data, Ref, pe) { - BUG(sp, "Match ergonomics - & pattern"); - } - TU_ARM(pattern.m_data, Tuple, e) { - // Get type info `(T, U, ...)` - if( m_temp_ivars.size() != e.sub_patterns.size() ) { - for(size_t i = 0; i < e.sub_patterns.size(); i ++) - m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() ); - } - decltype(m_temp_ivars) tuple; - for(const auto& ty : m_temp_ivars) - tuple.push_back(ty.clone()); - possible_type = ::HIR::TypeRef( ::std::move(tuple) ); - } - TU_ARM(pattern.m_data, SplitTuple, pe) { - // Can't get type information, tuple size is unkown - } - TU_ARM(pattern.m_data, Slice, e) { - // Can be either a [T] or [T; n]. Can't provide a hint - } - TU_ARM(pattern.m_data, SplitSlice, pe) { - // Can be either a [T] or [T; n]. Can't provide a hint - } - TU_ARM(pattern.m_data, StructValue, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, StructTuple, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, Struct, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, EnumValue, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern); + if( possible_type != ::HIR::TypeRef() ) + { + if( const auto* te = ty_p->m_data.opt_Infer() ) + { + context.possible_equate_type_unsize_to(te->index, possible_type); } - TU_ARM(pattern.m_data, EnumTuple, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + else if( is_fallback ) + { + DEBUG("Fallback equate " << possible_type); + context.equate_types(sp, *ty_p, possible_type); } - TU_ARM(pattern.m_data, EnumStruct, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + else + { } - } - if( possible_type != ::HIR::TypeRef() ) - { - DEBUG("Possible equate " << possible_type); - context.equate_types( sp, *ty_p, possible_type ); + + //if( is_fallback ) + //{ + // DEBUG("Possible equate " << possible_type); + // context.equate_types( sp, *ty_p, possible_type ); + //} } } @@ -6444,6 +6474,16 @@ namespace { context.equate_types_to_shadow(sp, t); } + // If the impl type is an unbounded ivar, and there's no trait args - don't bother searching + if( const auto* e = context.m_ivars.get_type(v.impl_ty).m_data.opt_Infer() ) + { + // TODO: ? + if( !e->is_lit() && v.params.m_types.empty() ) + { + return false; + } + } + // 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)); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 5db296ea..f94cdf26 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2445,6 +2445,8 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, t_cb_trait_impl_r callback ) const { + // TODO: Have a global cache of impls that don't reference either generics or ivars + static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << ""; }) << " for " << type); -- cgit v1.2.3