diff options
-rw-r--r-- | src/hir/path.cpp | 97 | ||||
-rw-r--r-- | src/hir/path.hpp | 5 | ||||
-rw-r--r-- | src/hir/type.cpp | 15 | ||||
-rw-r--r-- | src/hir_expand/ufcs_everything.cpp | 44 | ||||
-rw-r--r-- | src/hir_typeck/expr_check.cpp | 41 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 34 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 94 |
7 files changed, 229 insertions, 101 deletions
diff --git a/src/hir/path.cpp b/src/hir/path.cpp index 1552c8f3..0df8a6d2 100644 --- a/src/hir/path.cpp +++ b/src/hir/path.cpp @@ -224,6 +224,43 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const throw ""; } +::HIR::Compare HIR::PathParams::compare_with_placeholders(const Span& sp, const ::HIR::PathParams& x, ::HIR::t_cb_resolve_type resolve_placeholder) const +{ + using ::HIR::Compare; + + auto rv = Compare::Equal; + if( this->m_types.size() > 0 || x.m_types.size() > 0 ) { + if( this->m_types.size() != x.m_types.size() ) { + return Compare::Unequal; + } + for( unsigned int i = 0; i < x.m_types.size(); i ++ ) + { + auto rv2 = this->m_types[i].compare_with_placeholders( sp, x.m_types[i], resolve_placeholder ); + if( rv2 == Compare::Unequal ) + return Compare::Unequal; + if( rv2 == Compare::Fuzzy ) + rv = Compare::Fuzzy; + } + } + return rv; +} +::HIR::Compare HIR::GenericPath::compare_with_placeholders(const Span& sp, const ::HIR::GenericPath& x, ::HIR::t_cb_resolve_type resolve_placeholder) const +{ + using ::HIR::Compare; + + if( this->m_path.m_crate_name != x.m_path.m_crate_name ) + return Compare::Unequal; + if( this->m_path.m_components.size() != x.m_path.m_components.size() ) + return Compare::Unequal; + for(unsigned int i = 0; i < this->m_path.m_components.size(); i ++ ) + { + if( this->m_path.m_components[i] != x.m_path.m_components[i] ) + return Compare::Unequal; + } + + return this->m_params. compare_with_placeholders(sp, x.m_params, resolve_placeholder); +} + namespace { ::HIR::Compare compare_with_placeholders( const Span& sp, @@ -231,23 +268,7 @@ namespace { ::HIR::t_cb_resolve_type resolve_placeholder ) { - using ::HIR::Compare; - - auto rv = Compare::Equal; - if( l.m_types.size() > 0 || r.m_types.size() > 0 ) { - if( l.m_types.size() != r.m_types.size() ) { - return Compare::Unequal; - } - for( unsigned int i = 0; i < r.m_types.size(); i ++ ) - { - auto rv2 = l.m_types[i].compare_with_placeholders( sp, r.m_types[i], resolve_placeholder ); - if( rv2 == Compare::Unequal ) - return Compare::Unequal; - if( rv2 == Compare::Fuzzy ) - rv = Compare::Fuzzy; - } - } - return rv; + return l.compare_with_placeholders(sp, r, resolve_placeholder); } ::HIR::Compare compare_with_placeholders( const Span& sp, @@ -255,19 +276,7 @@ namespace { ::HIR::t_cb_resolve_type resolve_placeholder ) { - using ::HIR::Compare; - - if( l.m_path.m_crate_name != r.m_path.m_crate_name ) - return Compare::Unequal; - if( l.m_path.m_components.size() != r.m_path.m_components.size() ) - return Compare::Unequal; - for(unsigned int i = 0; i < l.m_path.m_components.size(); i ++ ) - { - if( l.m_path.m_components[i] != r.m_path.m_components[i] ) - return Compare::Unequal; - } - - return compare_with_placeholders(sp, l.m_params, r.m_params, resolve_placeholder); + return l.compare_with_placeholders(sp, r, resolve_placeholder); } } @@ -279,6 +288,34 @@ namespace { }\ } while(0) +::HIR::Compare HIR::TraitPath::compare_with_placeholders(const Span& sp, const TraitPath& x, t_cb_resolve_type resolve_placeholder) const +{ + auto rv = m_path .compare_with_placeholders(sp, x.m_path, resolve_placeholder); + if( rv == Compare::Unequal ) + return rv; + + // TODO: HRLs + + auto it_l = m_type_bounds.begin(); + auto it_r = x.m_type_bounds.begin(); + while( it_l != m_type_bounds.end() && it_r != x.m_type_bounds.end() ) + { + if( it_l->first != it_r->first ) { + return Compare::Unequal; + } + CMP( rv, it_l->second .compare_with_placeholders( sp, it_r->second, resolve_placeholder ) ); + ++ it_l; + ++ it_r; + } + + if( it_l != m_type_bounds.end() || it_r != x.m_type_bounds.end() ) + { + return Compare::Unequal; + } + + return rv; +} + ::HIR::Compare HIR::Path::compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const { if( this->m_data.tag() != x.m_data.tag() ) diff --git a/src/hir/path.hpp b/src/hir/path.hpp index a4ee9ca1..57a8330b 100644 --- a/src/hir/path.hpp +++ b/src/hir/path.hpp @@ -89,6 +89,8 @@ struct PathParams PathParams(PathParams&&) = default; PathParams& operator=(PathParams&&) = default; + Compare compare_with_placeholders(const Span& sp, const PathParams& x, t_cb_resolve_type resolve_placeholder) const; + bool operator==(const PathParams& x) const; bool operator!=(const PathParams& x) const { return !(*this == x); } bool operator<(const PathParams& x) const { return ord(x) == OrdLess; } @@ -111,6 +113,7 @@ public: GenericPath(::HIR::SimplePath sp, ::HIR::PathParams params); GenericPath clone() const; + Compare compare_with_placeholders(const Span& sp, const GenericPath& x, t_cb_resolve_type resolve_placeholder) const; bool operator==(const GenericPath& x) const; bool operator!=(const GenericPath& x) const { return !(*this == x); } @@ -136,6 +139,8 @@ public: const ::HIR::Trait* m_trait_ptr; TraitPath clone() const; + Compare compare_with_placeholders(const Span& sp, const TraitPath& x, t_cb_resolve_type resolve_placeholder) const; + bool operator==(const TraitPath& x) const; bool operator!=(const TraitPath& x) const { return !(*this == x); } diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 7a833a32..e51929c9 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -816,7 +816,20 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Equal; ), (TraitObject, - TODO(sp, "Compare " << *this << " and " << right); + if( le.m_markers.size() != re.m_markers.size() ) + return Compare::Unequal; + auto rv = le.m_trait .compare_with_placeholders( sp, re.m_trait, resolve_placeholder ); + if( rv == Compare::Unequal ) + return rv; + for( unsigned int i = 0; i < le.m_markers.size(); i ++ ) + { + auto rv2 = le.m_markers[i] .compare_with_placeholders( sp, re.m_markers[i], resolve_placeholder ); + if( rv2 == Compare::Unequal ) + return Compare::Unequal; + if( rv2 == Compare::Fuzzy ) + rv = Compare::Fuzzy; + } + return rv; ), (Array, if( le.size_val != re.size_val ) diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index 550b9517..c7c19d8c 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -4,6 +4,7 @@ * * hir_expand/ufcs_everything.cpp * - Expand all function calls (_CallMethod, and _CallValue) and operator overloads to _CallPath + * - Also handles borrow-unsize-deref for _Unsize on arrays (see comment in _Unsize) */ #include <hir/visitor.hpp> #include <hir/expr.hpp> @@ -649,7 +650,7 @@ namespace { langitem = method = "deref_mut"; break; case ::HIR::ValueUsage::Move: - TODO(sp, "Support moving out of indexed values"); + TODO(sp, "Support moving out of borrows"); break; } // Needs replacement, continue @@ -676,6 +677,47 @@ namespace { // - Dereference the result (which is an &-ptr) m_replacement = NEWNODE( mv$(node.m_res_type), Deref, sp, mv$(m_replacement) ); } + + + + void visit(::HIR::ExprNode_Unsize& node) override + { + ::HIR::ExprVisitorDef::visit(node); + + // HACK: The autoderef code has to run before usage information is avaliable, so emits "invalid" _Unsize nodes + // - Fix that. + if( node.m_value->m_res_type.m_data.is_Array() ) + { + const Span& sp = node.span(); + + ::HIR::BorrowType bt = ::HIR::BorrowType::Shared; + switch( node.m_usage ) + { + case ::HIR::ValueUsage::Unknown: + BUG(sp, "Unknown usage type of _Unsize value"); + break; + case ::HIR::ValueUsage::Borrow: + bt = ::HIR::BorrowType::Shared; + break; + case ::HIR::ValueUsage::Mutate: + bt = ::HIR::BorrowType::Unique; + break; + case ::HIR::ValueUsage::Move: + TODO(sp, "Support moving in _Unsize"); + break; + } + + auto ty_src = ::HIR::TypeRef::new_borrow(bt, node.m_value->m_res_type.clone()); + auto ty_dst = ::HIR::TypeRef::new_borrow(bt, node.m_res_type.clone()); + auto ty_dst2 = ty_dst.clone(); + // Borrow + node.m_value = NEWNODE( mv$(ty_src), Borrow, sp, bt, mv$(node.m_value) ); + // Unsize borrow + m_replacement = NEWNODE( mv$(ty_dst), Unsize, sp, mv$(node.m_value), mv$(ty_dst2) ); + // Deref + m_replacement = NEWNODE( mv$(node.m_res_type), Deref, sp, mv$(m_replacement) ); + } + } }; class OuterVisitor: public ::HIR::Visitor diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index fa12d363..71f28e8f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -285,18 +285,37 @@ namespace { const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - // Check unsizability (including trait impls) - // NOTE: Unsize applies inside borrows - TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (e), - ( - ERROR(sp, E0000, "Invalid unsizing operation to " << dst_ty << " from " << src_ty); - ), - (TraitObject, - ), - (Slice, - // TODO: Does unsize ever apply to arrays? - Yes. + + if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) + { + const auto& se = src_ty.m_data.as_Borrow(); + const auto& de = dst_ty.m_data.as_Borrow(); + if( se.type != de.type ) { + ERROR(sp, E0000, "Invalid unsizing operation to " << dst_ty << " from " << src_ty << " - Borrow class mismatch"); + } + const auto& src_ty = *se.inner; + const auto& dst_ty = *de.inner; + // Check unsizability (including trait impls) + // NOTE: Unsize applies inside borrows + TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (e), + ( + ERROR(sp, E0000, "Invalid unsizing operation to " << dst_ty << " from " << src_ty); + ), + (TraitObject, + ), + (Slice, + // TODO: Does unsize ever apply to arrays? - Yes. + ) ) - ) + } + else if( src_ty.m_data.is_Borrow() || dst_ty.m_data.is_Borrow() ) + { + ERROR(sp, E0000, "Invalid unsizing operation to " << dst_ty << " from " << src_ty); + } + else + { + TODO(sp, "Check for impl of Unsize<" << dst_ty << "> for " << src_ty); + } node.m_value->visit( *this ); } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index e8bf8842..4ffd4b2a 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2902,6 +2902,7 @@ const ::HIR::TypeRef& Context::get_var(const Span& sp, unsigned int idx) const { { ASSERT_BUG(span, ty_dst.m_data.is_Slice(), "Array should only ever autoderef to Slice"); + // HACK: Emit an invalid _Unsize op that is fixed once usage type is known. auto ty_dst_c = ty_dst.clone(); val_node = NEWNODE( mv$(ty_dst), span, _Unsize, mv$(val_node), mv$(ty_dst_c) ); DEBUG("- Unsize " << &*val_node << " -> " << val_node->m_res_type); @@ -3053,10 +3054,10 @@ namespace { TU_IFLET(::HIR::TypeRef::Data, ty_src.m_data, Array, src_array, context.equate_types(sp, *dst_slice.inner, *src_array.inner); - add_coerce_borrow(context, node_ptr, ty_dst, [&](auto& node_ptr) { - auto span = node_ptr->span(); - node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); - }); + auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone()); + auto ty_dst_b2 = ty_dst_b.clone(); + auto span = node_ptr->span(); + node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); context.m_ivars.mark_change(); return true; @@ -3161,10 +3162,11 @@ namespace { } // Add _Unsize operator - add_coerce_borrow(context, node_ptr, ty_dst, [&](auto& node_ptr) { - auto span = node_ptr->span(); - node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); - }); + auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone()); + auto ty_dst_b2 = ty_dst_b.clone(); + auto span = node_ptr->span(); + node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); + return true; ) ) @@ -3196,10 +3198,11 @@ namespace { }); if( found ) { DEBUG("- Unsize " << &*node_ptr << " -> " << ty_dst); - add_coerce_borrow(context, node_ptr, ty_dst, [&](auto& node_ptr) { - auto span = node_ptr->span(); - node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); - }); + auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone()); + auto ty_dst_b2 = ty_dst_b.clone(); + auto span = node_ptr->span(); + node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); + return true; } } @@ -3233,11 +3236,8 @@ namespace { { DEBUG("- CoerceUnsize " << &*node_ptr << " -> " << ty_dst); - TODO(sp, "Add Coerce op applying to pointer type for " << ty_src << " -> " << ty_dst); - //add_coerce_borrow(context, node_ptr, ty_dst, [&](auto& node_ptr) { - // auto span = node_ptr->span(); - // node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); - // }); + auto span = node_ptr->span(); + node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); return true; } } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index dc890495..4a540c14 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -876,49 +876,61 @@ namespace { const auto& ty_out = node.m_res_type; const auto& ty_in = node.m_value->m_res_type; - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_out.m_data), (e), - ( - TODO(node.span(), "MIR _Unsize to " << ty_out); - ), - // TODO: Unsize custom types containing a ?Size generic - See the Unsize trait - //(Path, - // ), - //(Generic, - // ), - (Slice, - if( ty_in.m_data.is_Array() ) - { - const auto& in_array = ty_in.m_data.as_Array(); - auto size_lval = m_builder.lvalue_or_temp( node.span(), ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::Constant( static_cast<uint64_t>(in_array.size_val) ) ); - m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(size_lval) }) ); - } - else if( ty_in.m_data.is_Generic() ) - { - // HACK: FixedSizeArray uses `A: Unsize<[T]>` which will lead to the above code not working (as the size isn't known). - // - Maybe _Meta on the `&A` would work as a stopgap (since A: Sized, it won't collide with &[T] or similar) - auto size_lval = m_builder.lvalue_or_temp( node.span(), ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::RValue::make_DstMeta({ ptr_lval.clone() }) ); - m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(size_lval) }) ); - } - else - { - ASSERT_BUG(node.span(), ty_in.m_data.is_Array(), "Unsize to slice from non-array - " << ty_in); - } - ), - (TraitObject, - // TODO: Obtain the vtable if the destination is a trait object - // vtable exists as an unnamable associated type + + if( ty_out.m_data.is_Borrow() && ty_in.m_data.is_Borrow() ) + { + const auto& oe = ty_out.m_data.as_Borrow(); + const auto& ie = ty_in.m_data.as_Borrow(); + const auto& ty_out = *oe.inner; + const auto& ty_in = *ie.inner; + TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_out.m_data), (e), + ( + TODO(node.span(), "MIR _Unsize to " << ty_out); + ), + // TODO: Unsize custom types containing a ?Size generic - See the Unsize trait + //(Path, + // ), + //(Generic, + // ), + (Slice, + if( ty_in.m_data.is_Array() ) + { + const auto& in_array = ty_in.m_data.as_Array(); + auto size_lval = m_builder.lvalue_or_temp( node.span(), ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::Constant( static_cast<uint64_t>(in_array.size_val) ) ); + m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(size_lval) }) ); + } + else if( ty_in.m_data.is_Generic() ) + { + // HACK: FixedSizeArray uses `A: Unsize<[T]>` which will lead to the above code not working (as the size isn't known). + // - Maybe _Meta on the `&A` would work as a stopgap (since A: Sized, it won't collide with &[T] or similar) + auto size_lval = m_builder.lvalue_or_temp( node.span(), ::HIR::TypeRef(::HIR::CoreType::Usize), ::MIR::RValue::make_DstMeta({ ptr_lval.clone() }) ); + m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(size_lval) }) ); + } + else + { + ASSERT_BUG(node.span(), ty_in.m_data.is_Array(), "Unsize to slice from non-array - " << ty_in); + } + ), + (TraitObject, + // TODO: Obtain the vtable if the destination is a trait object + // vtable exists as an unnamable associated type - ::HIR::Path vtable { ty_in.clone(), e.m_trait.m_path.clone(), "#vtable" }; - ::HIR::TypeRef vtable_type { {} }; - auto vtable_lval = m_builder.lvalue_or_temp( - node.span(), - ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, mv$(vtable_type)), - ::MIR::RValue( ::MIR::Constant::make_ItemAddr(mv$(vtable)) ) - ); - - m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(vtable_lval) }) ); + ::HIR::Path vtable { ty_in.clone(), e.m_trait.m_path.clone(), "#vtable" }; + ::HIR::TypeRef vtable_type { {} }; + auto vtable_lval = m_builder.lvalue_or_temp( + node.span(), + ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, mv$(vtable_type)), + ::MIR::RValue( ::MIR::Constant::make_ItemAddr(mv$(vtable)) ) + ); + + m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(vtable_lval) }) ); + ) ) - ) + } + else + { + TODO(node.span(), "Support emitting CoerceUnsized-based _Unsize ops in MIR - " << ty_in << " -> " << ty_out); + } } void visit(::HIR::ExprNode_Index& node) override { |