diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_expand/closures.cpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/expr_check.cpp | 61 | ||||
-rw-r--r-- | src/hir_typeck/static.cpp | 237 | ||||
-rw-r--r-- | src/hir_typeck/static.hpp | 2 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 2 |
5 files changed, 286 insertions, 17 deletions
diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index 180ed89a..5b4fd722 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -151,6 +151,7 @@ namespace { if( binding_it->second != ::HIR::ValueUsage::Move ) { auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared); + visit_type(m_replacement->m_res_type); m_replacement->m_res_type = ::HIR::TypeRef::new_borrow( bt, mv$(m_replacement->m_res_type) ); m_replacement = NEWNODE(node.m_res_type.clone(), Deref, node.span(), mv$(m_replacement)); } diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index d0fe6a5d..66fdcb14 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -22,12 +22,15 @@ namespace { const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; + ::HIR::SimplePath m_lang_Index; + public: ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type): m_resolve(res), //m_args(args), ret_type(ret_type) { + m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index"); } void visit_root(::HIR::ExprPtr& node_ptr) @@ -255,8 +258,7 @@ namespace { { TRACE_FUNCTION_F(&node << " ... [ ... ]"); check_associated_type(node.span(), - node.m_res_type, - this->get_lang_item_path(node.span(), "index"), { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target" + node.m_res_type, m_lang_Index, { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target" ); node.m_value->visit( *this ); @@ -333,7 +335,10 @@ namespace { const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) + if( src_ty == dst_ty ) + { + } + else 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(); @@ -363,10 +368,20 @@ namespace { void visit(::HIR::ExprNode_Deref& node) override { TRACE_FUNCTION_F(&node << " *..."); - check_associated_type(node.span(), - node.m_res_type, - this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target" - ); + const auto& ty = node.m_value->m_res_type; + + if( ty.m_data.is_Pointer() ) { + check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Pointer().inner); + } + else if( ty.m_data.is_Borrow() ) { + check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Borrow().inner); + } + else { + check_associated_type(node.span(), + node.m_res_type, + this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target" + ); + } node.m_value->visit( *this ); } @@ -768,7 +783,10 @@ namespace { ), (TraitBound, auto real_type = monomorphise_type_with(sp, be.type, cache.m_monomorph_cb); + m_resolve.expand_associated_types(sp, real_type); auto real_trait = monomorphise_genericpath_with(sp, be.trait.m_path, cache.m_monomorph_cb, false); + for(auto& t : real_trait.m_params.m_types) + m_resolve.expand_associated_types(sp, t); DEBUG("Bound " << be.type << ": " << be.trait); DEBUG("= (" << real_type << ": " << real_trait << ")"); const auto& trait_params = real_trait.m_params; @@ -783,6 +801,7 @@ namespace { ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait); auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); + m_resolve.expand_associated_types(sp, other_ty); check_associated_type(sp, other_ty, type_trait_path.m_path, type_trait_path.m_params, real_type, assoc.first.c_str()); } @@ -1047,10 +1066,29 @@ namespace { const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ity, const char* name ) const { - // TODO: Actually check. - #if 0 - bool found = m_resolve.find_impl(sp, trait, ¶ms, ity, [&](auto impl, bool fuzzy){ - + if( trait == m_lang_Index && ity.m_data.is_Array() ) { + if(name) + { + if( res != *ity.m_data.as_Array().inner ) { + ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << *ity.m_data.as_Array().inner); + } + } + return ; + } + bool found = m_resolve.find_impl(sp, trait, ¶ms, ity, [&](auto impl, bool fuzzy) { + if( name ) + { + auto atyv = impl.get_type(name); + m_resolve.expand_associated_types(sp, atyv); + if( atyv == ::HIR::TypeRef() ) + { + // TODO: Check that `res` is <ity as trait>::name + } + else if( res != atyv ) + { + ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << atyv); + } + } return true; }); @@ -1058,7 +1096,6 @@ namespace { { ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity); } - #endif } const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 83299909..b46567fd 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -109,11 +109,13 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); } } - //else if( trait_path == m_lang_Unsize ) { - // if( true ) { - // return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); - // } - //} + else if( trait_path == m_lang_Unsize ) { + ASSERT_BUG(sp, trait_params, "TODO: Support no params for Unzie"); + const auto& dst_ty = trait_params->m_types.at(0); + if( this->can_unsize(sp, dst_ty, type) ) { + return found_cb( ImplRef(&type, trait_params, &null_assoc), false ); + } + } } // --- MAGIC IMPLS --- @@ -1177,6 +1179,43 @@ bool StaticTraitResolve::iterate_bounds( ::std::function<bool(const ::HIR::Gener } return false; } + + +bool StaticTraitResolve::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const +{ + const auto& trait_ref = m_crate.get_trait_by_path(sp, pe.trait.m_path); + ASSERT_BUG(sp, trait_ref.m_types.count( pe.item ) != 0, "Trait " << pe.trait.m_path << " doesn't contain an associated type " << pe.item); + const auto& aty_def = trait_ref.m_types.find(pe.item)->second; + + for(const auto& bound : aty_def.m_trait_bounds) + { + if( cb(bound) ) + return true; + } + // Search `<Self as Trait>::Name` bounds on the trait itself + for(const auto& bound : trait_ref.m_params.m_bounds) + { + if( ! bound.is_TraitBound() ) continue ; + const auto& be = bound.as_TraitBound(); + + if( ! be.type.m_data.is_Path() ) continue ; + if( ! be.type.m_data.as_Path().binding.is_Opaque() ) continue ; + + const auto& be_type_pe = be.type.m_data.as_Path().path.m_data.as_UfcsKnown(); + if( *be_type_pe.type != ::HIR::TypeRef("Self", 0xFFFF) ) + continue ; + if( be_type_pe.trait.m_path != pe.trait.m_path ) + continue ; + if( be_type_pe.item != pe.item ) + continue ; + + if( cb(be.trait) ) + return true; + } + + return false; +} + // ------------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------- @@ -1408,6 +1447,194 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) throw ""; } +bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const +{ + TRACE_FUNCTION_F(dst_ty << " <- " << src_ty); + + ASSERT_BUG(sp, !dst_ty.m_data.is_Infer(), "_ seen after inferrence - " << dst_ty); + ASSERT_BUG(sp, !src_ty.m_data.is_Infer(), "_ seen after inferrence - " << src_ty); + + { + //ASSERT_BUG(sp, dst_ty != src_ty, "Equal types for can_unsize - " << dst_ty << " <-" << src_ty ); + if( dst_ty == src_ty ) + return true; + } + + { + bool found_bound = this->iterate_bounds([&](const auto& gb){ + if(!gb.is_TraitBound()) + return false; + const auto& be = gb.as_TraitBound(); + if(be.trait.m_path.m_path != m_lang_Unsize) + return false; + const auto& be_dst = be.trait.m_path.m_params.m_types.at(0); + + if( src_ty != be.type ) return false; + if( dst_ty != be_dst ) return false; + return true; + }); + if( found_bound ) + { + return ::HIR::Compare::Equal; + } + } + + // Associated types, check the bounds in the trait. + if( src_ty.m_data.is_Path() && src_ty.m_data.as_Path().path.m_data.is_UfcsKnown() ) + { + const auto& pe = src_ty.m_data.as_Path().path.m_data.as_UfcsKnown(); + auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); + auto found_bound = this->iterate_aty_bounds(sp, pe, [&](const ::HIR::TraitPath& bound) { + if( bound.m_path.m_path != m_lang_Unsize ) + return false; + const auto& be_dst_tpl = bound.m_path.m_params.m_types.at(0); + ::HIR::TypeRef tmp_ty; + const auto& be_dst = (monomorphise_type_needed(be_dst_tpl) ? tmp_ty = monomorphise_type_with(sp, be_dst_tpl, monomorph_cb) : be_dst_tpl); + + if( dst_ty != be_dst ) return false; + return true; + }); + if( found_bound ) + { + return true; + } + } + + // Struct<..., T, ...>: Unsize<Struct<..., U, ...>> + if( dst_ty.m_data.is_Path() && src_ty.m_data.is_Path() ) + { + bool dst_is_unsizable = dst_ty.m_data.as_Path().binding.is_Struct() && dst_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize; + bool src_is_unsizable = src_ty.m_data.as_Path().binding.is_Struct() && src_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize; + if( dst_is_unsizable || src_is_unsizable ) + { + DEBUG("Struct unsize? " << dst_ty << " <- " << src_ty); + const auto& str = *dst_ty.m_data.as_Path().binding.as_Struct(); + const auto& dst_gp = dst_ty.m_data.as_Path().path.m_data.as_Generic(); + const auto& src_gp = src_ty.m_data.as_Path().path.m_data.as_Generic(); + + if( dst_gp == src_gp ) + { + DEBUG("Can't Unsize, destination and source are identical"); + return false; + } + else if( dst_gp.m_path == src_gp.m_path ) + { + DEBUG("Checking for Unsize " << dst_gp << " <- " << src_gp); + // Structures are equal, add the requirement that the ?Sized parameter also impl Unsize + const auto& dst_inner = dst_gp.m_params.m_types.at(str.m_markings.unsized_param); + const auto& src_inner = src_gp.m_params.m_types.at(str.m_markings.unsized_param); + return this->can_unsize(sp, dst_inner, src_inner); + } + else + { + DEBUG("Can't Unsize, destination and source are different structs"); + return false; + } + } + } + + // (Trait) <- Foo + if( const auto* de = dst_ty.m_data.opt_TraitObject() ) + { + // TODO: Check if src_ty is !Sized + // - Only allowed if the source is a trait object with the same data trait and lesser bounds + + DEBUG("TraitObject unsize? " << dst_ty << " <- " << src_ty); + + // (Trait) <- (Trait+Foo) + if( const auto* se = src_ty.m_data.opt_TraitObject() ) + { + // 1. Data trait must be the same + if( de->m_trait != se->m_trait ) + { + return ::HIR::Compare::Unequal; + } + + // 2. Destination markers must be a strict subset + for(const auto& mt : de->m_markers) + { + bool found = false; + for(const auto& omt : se->m_markers) { + if( omt == mt ) { + found = true; + break; + } + } + if( !found ) { + // Return early. + return false; + } + } + + return true; + } + + bool good; + + ::HIR::TypeRef::Data::Data_TraitObject tmp_e; + tmp_e.m_trait.m_path = de->m_trait.m_path.m_path; + + // Check data trait first. + if( de->m_trait.m_path.m_path == ::HIR::SimplePath() ) { + ASSERT_BUG(sp, de->m_markers.size() > 0, "TraitObject with no traits - " << dst_ty); + good = true; + } + else { + good = false; + find_impl(sp, de->m_trait.m_path.m_path, de->m_trait.m_path.m_params, src_ty, + [&](const auto impl, auto fuzz) { + assert( !fuzz ); + good = true; + for(const auto& aty : de->m_trait.m_type_bounds) { + auto atyv = impl.get_type(aty.first.c_str()); + if( atyv == ::HIR::TypeRef() ) + { + // Get the trait from which this associated type comes. + // Insert a UfcsKnown path for that + auto p = ::HIR::Path( src_ty.clone(), de->m_trait.m_path.clone(), aty.first ); + // Run EAT + atyv = ::HIR::TypeRef::new_path( mv$(p), {} ); + } + this->expand_associated_types(sp, atyv); + if( aty.second != atyv ) { + good = false; + DEBUG("ATY " << aty.first << " mismatch - " << aty.second << " != " << atyv); + } + } + return true; + }); + } + + // Then markers + auto cb = [&](const auto impl, auto ){ + tmp_e.m_markers.back().m_params = impl.get_trait_params(); + return true; + }; + for(const auto& marker : de->m_markers) + { + if(!good) break; + tmp_e.m_markers.push_back( marker.m_path ); + good &= this->find_impl(sp, marker.m_path, marker.m_params, src_ty, cb); + } + + return good; + } + + // [T] <- [T; n] + if( const auto* de = dst_ty.m_data.opt_Slice() ) + { + if( const auto* se = src_ty.m_data.opt_Array() ) + { + DEBUG("Array unsize? " << *de->inner << " <- " << *se->inner); + return *se->inner == *de->inner; + } + } + + DEBUG("Can't unsize, no rules matched"); + return ::HIR::Compare::Unequal; + +} + bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const { // If `T: Copy`, then it can't need drop glue diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 16302218..4c094218 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -170,6 +170,7 @@ public: ) const; /// bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; + bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const; // -------------- @@ -177,6 +178,7 @@ public: // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; + bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const; /// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop bool type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 625731cc..69f787c0 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -814,6 +814,7 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl drop_scope_values(scope_def); // Emit ScopeEnd for all controlled values + #if 0 ::MIR::Statement::Data_ScopeEnd se; if(const auto* e = scope_def.data.opt_Variables() ) { se.vars = e->vars; @@ -827,6 +828,7 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl if( !se.vars.empty() || !se.tmps.empty() ) { this->push_stmt(sp, ::MIR::Statement( mv$(se) )); } + #endif } // 3. Pop scope (last because `drop_scope_values` uses the stack) |