From: Philip Herron <[email protected]>

Where constraints are annoying so we need to do it in two passes.

 1. Register bounds on the regular single segment TypePaths so like P: Deref
 2. Then register regular type bindings like I::Item or Item = U::Item

As they can be order dependant as the initial predicate needs added to then
param decls then onto whatever projections after.

Fixes Rust-GCC/gccrs#4864

gcc/rust/ChangeLog:

        * hir/tree/rust-hir-item.h: missing non const helper.
        * typecheck/rust-hir-type-check-base.h: new defer_bindings.
        * typecheck/rust-hir-type-check-implitem.cc 
(TypeCheckTopLevelExternItem::visit): new helper
        (TypeCheckImplItem::resolve_function_signature): Likewise.
        (TypeCheckImplItem::visit): Likewise.
        * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit):  
Likewise.
        (TypeCheckItem::resolve_function_signature):  Likewise.
        (TypeCheckItem::resolve_impl_block_substitutions):  Likewise.
        * typecheck/rust-hir-type-check-type.cc 
(ResolveWhereClauseItem::Resolve): new helper
        (ResolveWhereClauseItem::visit): support defer.
        * typecheck/rust-hir-type-check-type.h: update header.
        * typecheck/rust-hir-type-check.cc 
(TraitItemReference::get_type_from_fn): call new helper
        * typecheck/rust-tyty-bounds.cc: defer flag

gcc/testsuite/ChangeLog:

        * rust/compile/issue-4864.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/112b46e3f8e3b81f28e90a7c8ebd1789592d31cb

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4864: https://github.com/Rust-GCC/gccrs/issues/4864

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4875

 gcc/rust/hir/tree/rust-hir-item.h             |  2 +
 gcc/rust/typecheck/rust-hir-type-check-base.h |  3 +-
 .../typecheck/rust-hir-type-check-implitem.cc | 24 ++---
 .../typecheck/rust-hir-type-check-item.cc     | 36 +++-----
 .../typecheck/rust-hir-type-check-type.cc     | 89 ++++++++++++++++++-
 gcc/rust/typecheck/rust-hir-type-check-type.h |  8 +-
 gcc/rust/typecheck/rust-hir-type-check.cc     | 10 +--
 gcc/rust/typecheck/rust-tyty-bounds.cc        | 13 ++-
 gcc/testsuite/rust/compile/issue-4864.rs      | 22 +++++
 9 files changed, 150 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4864.rs

diff --git a/gcc/rust/hir/tree/rust-hir-item.h 
b/gcc/rust/hir/tree/rust-hir-item.h
index a956e0b53..9a572bf92 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -2559,6 +2559,8 @@ public:
     return where_clause;
   }
 
+  WARN_UNUSED_RESULT WhereClause &get_where_clause () { return where_clause; }
+
   ExternalFunctionItem (
     Analysis::NodeMapping mappings, Identifier item_name,
     std::vector<std::unique_ptr<GenericParam>> generic_params,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h 
b/gcc/rust/typecheck/rust-hir-type-check-base.h
index 3a9df89a5..61e545149 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -53,7 +53,8 @@ protected:
     HIR::TypePath &path,
     tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
     BoundPolarity polarity = BoundPolarity::RegularBound,
-    bool is_qualified_type = false, bool is_super_trait = false);
+    bool is_qualified_type = false, bool is_super_trait = false,
+    bool defer_bindings = false);
 
   bool check_for_unconstrained (
     const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 9fb0d70a3..8c65390f7 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -80,14 +80,8 @@ TypeCheckTopLevelExternItem::visit 
(HIR::ExternalFunctionItem &function)
     }
 
   TyTy::RegionConstraints region_constraints;
-  if (function.has_where_clause ())
-    {
-      for (auto &where_clause_item : function.get_where_clause ().get_items ())
-       {
-         ResolveWhereClauseItem::Resolve (*where_clause_item,
-                                          region_constraints);
-       }
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_return_type ())
@@ -254,11 +248,8 @@ TypeCheckImplItem::resolve_function_signature 
(HIR::Function &function)
                            function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : function.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item.get (),
-                                      region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_function_return_type ())
@@ -510,11 +501,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias)
   context->insert_type (alias.get_mappings (), actual_type);
   result = actual_type;
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item.get (),
-                                      region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (alias.get_where_clause (),
+                                  region_constraints);
 }
 
 TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 2f2005b71..4d02e3b5c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -310,10 +310,8 @@ TypeCheckItem::visit (HIR::TypeAlias &alias)
   context->insert_type (alias.get_mappings (), actual_type);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (alias.get_where_clause (),
+                                  region_constraints);
   infered = actual_type;
 }
 
@@ -329,10 +327,8 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl)
                            struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (),
+                                  region_constraints);
 
   // Process #[repr(X)] attribute, if any
   const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
@@ -410,10 +406,8 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
                            struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (),
+                                  region_constraints);
 
   // Process #[repr(X)] attribute, if any
   const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
@@ -577,10 +571,8 @@ TypeCheckItem::visit (HIR::Union &union_decl)
                            union_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (union_decl.get_where_clause (),
+                                  region_constraints);
 
   std::vector<TyTy::StructFieldType *> fields;
   for (auto &variant : union_decl.get_variants ())
@@ -833,10 +825,8 @@ TypeCheckItem::resolve_function_signature (HIR::Function 
&function)
                            function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : function.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_function_return_type ())
@@ -1053,10 +1043,8 @@ TypeCheckItem::resolve_impl_block_substitutions 
(HIR::ImplBlock &impl_block,
                            impl_block.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (impl_block.get_where_clause (),
+                                  region_constraints);
 
   auto specified_bound = TyTy::TypeBoundPredicate::error ();
   TraitReference *trait_reference = &TraitReference::error_node ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc 
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index 84baab6ff..5fe75cf48 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -1023,6 +1023,64 @@ ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem 
&item,
     }
 }
 
+void
+ResolveWhereClauseItem::Resolve (HIR::WhereClause &clause,
+                                TyTy::RegionConstraints &region_constraints)
+{
+  ResolveWhereClauseItem resolver (region_constraints);
+
+  class PlainTypePath : public HIR::HIRTypeVisitor
+  {
+  public:
+    bool matches = false;
+
+    void visit (HIR::TypePathSegmentFunction &segment) override {}
+    void visit (HIR::QualifiedPathInType &path) override {}
+    void visit (HIR::TraitBound &bound) override {}
+    void visit (HIR::ImplTraitType &type) override {}
+    void visit (HIR::TraitObjectType &type) override {}
+    void visit (HIR::ParenthesisedType &type) override {}
+    void visit (HIR::TupleType &type) override {}
+    void visit (HIR::NeverType &type) override {}
+    void visit (HIR::RawPointerType &type) override {}
+    void visit (HIR::ReferenceType &type) override {}
+    void visit (HIR::ArrayType &type) override {}
+    void visit (HIR::SliceType &type) override {}
+    void visit (HIR::InferredType &type) override {}
+    void visit (HIR::BareFunctionType &type) override {}
+
+    void visit (HIR::TypePath &path) override
+    {
+      bool is_single = path.get_segments ().size () == 1;
+      bool final_seg_is_reg
+       = path.get_final_segment ().get_type () == HIR::TypePathSegment::REG;
+
+      matches = is_single && final_seg_is_reg;
+    }
+  };
+
+  resolver.defer_bindings = true;
+  for (auto &item : clause.get_items ())
+    if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND)
+      {
+       auto &bound = static_cast<HIR::TypeBoundWhereClauseItem &> (*item);
+       PlainTypePath plain;
+       bound.get_bound_type ().accept_vis (plain);
+       if (plain.matches)
+         resolver.visit (bound);
+      }
+
+  resolver.defer_bindings = false;
+  resolver.complete_bindings = true;
+  for (auto &item : clause.get_items ())
+    {
+      if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND)
+       resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (*item));
+      else
+       Resolve (*item, region_constraints);
+    }
+}
+
 void
 ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item)
 {
@@ -1060,6 +1118,9 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
     = TypeCheckType::Resolve (binding_type_path,
                              TypeCheckType::ResolutionMode::CANONICAL);
 
+  if (defer_bindings && binding->get_kind () != TyTy::TypeKind::PARAM)
+    return;
+
   // FIXME double check there might be a trait cycle here see TypeParam 
handling
 
   std::vector<TyTy::TypeBoundPredicate> specified_bounds;
@@ -1072,13 +1133,17 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
            auto *b = static_cast<HIR::TraitBound *> (bound.get ());
 
            TyTy::TypeBoundPredicate predicate
-             = get_predicate_from_bound (b->get_path (), binding_type_path);
+             = get_predicate_from_bound (b->get_path (), binding_type_path,
+                                         BoundPolarity::RegularBound, false,
+                                         false, defer_bindings);
            if (!predicate.is_error ())
              specified_bounds.push_back (std::move (predicate));
          }
          break;
        case HIR::TypeParamBound::BoundType::LIFETIME:
          {
+           if (defer_bindings)
+             break;
            if (auto param = binding->try_as<TyTy::ParamType> ())
              {
                auto *b = static_cast<HIR::Lifetime *> (bound.get ());
@@ -1098,7 +1163,27 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
          break;
        }
     }
-  binding->inherit_bounds (specified_bounds);
+
+  for (const auto &predicate : specified_bounds)
+    {
+      bool replaced = false;
+      if (complete_bindings)
+       {
+         for (auto &bound : binding->get_specified_bounds ())
+           {
+             if (bound.get_id () == predicate.get_id ()
+                 && bound.get_locus () == predicate.get_locus ())
+               {
+                 bound = predicate;
+                 replaced = true;
+                 break;
+               }
+           }
+       }
+
+      if (!replaced)
+       binding->inherit_bound (predicate);
+    }
 }
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h 
b/gcc/rust/typecheck/rust-hir-type-check-type.h
index 9cc0fdbc3..ee1d0c97d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.h
@@ -132,7 +132,7 @@ class ResolveWhereClauseItem : public TypeCheckBase
   TyTy::RegionConstraints &region_constraints;
 
 public:
-  static void Resolve (HIR::WhereClauseItem &item,
+  static void Resolve (HIR::WhereClause &clause,
                       TyTy::RegionConstraints &region_constraints);
 
 protected:
@@ -140,6 +140,12 @@ protected:
   void visit (HIR::TypeBoundWhereClauseItem &item);
 
 private:
+  static void Resolve (HIR::WhereClauseItem &item,
+                      TyTy::RegionConstraints &region_constraints);
+
+  bool defer_bindings = false;
+  bool complete_bindings = false;
+
   ResolveWhereClauseItem (TyTy::RegionConstraints &region_constraints)
     : region_constraints (region_constraints)
   {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc 
b/gcc/rust/typecheck/rust-hir-type-check.cc
index d111207b7..d4c21d09c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -169,7 +169,6 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
   std::vector<TyTy::SubstitutionParamMapping> substitutions
     = inherited_substitutions;
 
-  TyTy::RegionConstraints region_constraints;
   HIR::TraitFunctionDecl &function = fn.get_decl ();
   if (function.has_generics ())
     {
@@ -180,12 +179,9 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
                                           ABI::RUST);
     }
 
-  if (function.has_where_clause ())
-    {
-      for (auto &where_clause_item : function.get_where_clause ().get_items ())
-       ResolveWhereClauseItem::Resolve (*where_clause_item,
-                                        region_constraints);
-    }
+  TyTy::RegionConstraints region_constraints;
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_return_type ())
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc 
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 0240a635c..bb2c5ed14 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -261,7 +261,8 @@ TyTy::TypeBoundPredicate
 TypeCheckBase::get_predicate_from_bound (
   HIR::TypePath &type_path,
   tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
-  BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait)
+  BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait,
+  bool defer_bindings)
 {
   TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error ();
   bool already_resolved
@@ -340,7 +341,7 @@ TypeCheckBase::get_predicate_from_bound (
 
        std::vector<HIR::GenericArgsBinding> bindings;
 
-       if (fn.has_return_type ())
+       if (fn.has_return_type () && !defer_bindings)
          {
            TypeCheckType::Resolve (fn.get_return_type ());
 
@@ -377,6 +378,9 @@ TypeCheckBase::get_predicate_from_bound (
                               args.get_locus ());
     }
 
+  if (defer_bindings)
+    args.get_binding_args ().clear ();
+
   // we try to apply generic arguments when they are non empty and or when the
   // predicate requires them so that we get the relevant Foo expects x number
   // arguments but got zero see test case rust/compile/traits12.rs
@@ -387,8 +391,9 @@ TypeCheckBase::get_predicate_from_bound (
                                         is_super_trait);
     }
 
-  context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
-                                     predicate);
+  if (!defer_bindings)
+    context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
+                                       predicate);
 
   return predicate;
 }
diff --git a/gcc/testsuite/rust/compile/issue-4864.rs 
b/gcc/testsuite/rust/compile/issue-4864.rs
new file mode 100644
index 000000000..c05000a3c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4864.rs
@@ -0,0 +1,22 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+trait Iterator {
+    type Item;
+}
+trait IntoIterator {
+    type Item;
+    type IntoIter: Iterator<Item = Self::Item>;
+}
+pub struct Flatten<I, U> {
+    pub inner: I,
+    pub extra: U,
+}
+impl<I, U> Iterator for Flatten<I, U>
+where
+    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
+    U: Iterator,
+{
+    type Item = U::Item;
+}

base-commit: cad63612b27d0e7bfc30eb8e548ad145ac16922a
-- 
2.55.0

Reply via email to