From: Philip Herron <herron.phi...@googlemail.com>

We need to recursively check the super traits of the predicate the Self
type is trying to implement. Otherwise its cannot implement it.

Fixes Rust-GCC#3553

gcc/rust/ChangeLog:

        * typecheck/rust-hir-type-check-item.cc 
(TypeCheckItem::resolve_impl_block_substitutions):
        Track the polarity
        * typecheck/rust-tyty-bounds.cc 
(TypeBoundPredicate::validate_type_implements_this):
        new validator
        * typecheck/rust-tyty.h: new prototypes

gcc/testsuite/ChangeLog:

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

Signed-off-by: Philip Herron <herron.phi...@googlemail.com>
---
 .../typecheck/rust-hir-type-check-item.cc     | 13 +++-
 gcc/rust/typecheck/rust-tyty-bounds.cc        | 59 +++++++++++++++++++
 gcc/rust/typecheck/rust-tyty.h                |  8 +++
 gcc/testsuite/rust/compile/issue-3553.rs      | 18 ++++++
 4 files changed, 95 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-3553.rs

diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index a003848cce0..97749214351 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -725,11 +725,11 @@ TypeCheckItem::resolve_impl_block_substitutions 
(HIR::ImplBlock &impl_block,
 
       // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
       // for example
-      specified_bound = get_predicate_from_bound (ref, impl_block.get_type ());
+      specified_bound = get_predicate_from_bound (ref, impl_block.get_type (),
+                                                 impl_block.get_polarity ());
     }
 
   TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ());
-
   if (self->is<TyTy::ErrorType> ())
     {
       // we cannot check for unconstrained type arguments when the Self type is
@@ -771,7 +771,14 @@ TypeCheckItem::validate_trait_impl_block (
 
       // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
       // for example
-      specified_bound = get_predicate_from_bound (ref, impl_block.get_type ());
+      specified_bound = get_predicate_from_bound (ref, impl_block.get_type (),
+                                                 impl_block.get_polarity ());
+
+      // need to check that if this specified bound has super traits does this
+      // Self
+      // implement them?
+      specified_bound.validate_type_implements_super_traits (
+       *self, impl_block.get_type (), impl_block.get_trait_ref ());
     }
 
   bool is_trait_impl_block = !trait_reference->is_error ();
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc 
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 65f24c0aa2a..e028a0af80b 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -828,6 +828,65 @@ TypeBoundPredicate::is_equal (const TypeBoundPredicate 
&other) const
   return true;
 }
 
+bool
+TypeBoundPredicate::validate_type_implements_super_traits (
+  TyTy::BaseType &self, HIR::Type &impl_type, HIR::Type &trait) const
+{
+  if (get_polarity () != BoundPolarity::RegularBound)
+    return true;
+
+  auto &ptref = *get ();
+  for (auto &super : super_traits)
+    {
+      if (super.get_polarity () != BoundPolarity::RegularBound)
+       continue;
+
+      if (!super.validate_type_implements_this (self, impl_type, trait))
+       {
+         auto &sptref = *super.get ();
+
+         // emit error
+         std::string fixit1
+           = "required by this bound in: " + ptref.get_name ();
+         std::string fixit2 = "the trait " + sptref.get_name ()
+                              + " is not implemented for "
+                              + impl_type.as_string ();
+
+         rich_location r (line_table, trait.get_locus ());
+         r.add_fixit_insert_after (super.get_locus (), fixit1.c_str ());
+         r.add_fixit_insert_after (trait.get_locus (), fixit2.c_str ());
+         rust_error_at (r, ErrorCode::E0277,
+                        "the trait bound %<%s: %s%> is not satisfied",
+                        impl_type.as_string ().c_str (),
+                        sptref.get_name ().c_str ());
+
+         return false;
+       }
+
+      if (!super.validate_type_implements_super_traits (self, impl_type, 
trait))
+       return false;
+    }
+
+  return true;
+}
+
+bool
+TypeBoundPredicate::validate_type_implements_this (TyTy::BaseType &self,
+                                                  HIR::Type &impl_type,
+                                                  HIR::Type &trait) const
+{
+  const auto &ptref = *get ();
+  auto probed_bounds = Resolver::TypeBoundsProbe::Probe (&self);
+  for (auto &elem : probed_bounds)
+    {
+      auto &tref = *(elem.first);
+      if (ptref.is_equal (tref))
+       return true;
+    }
+
+  return false;
+}
+
 // trait item reference
 
 const Resolver::TraitItemReference *
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 0bfd29d98bb..e814f07f445 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -578,6 +578,14 @@ public:
 
   bool is_equal (const TypeBoundPredicate &other) const;
 
+  bool validate_type_implements_super_traits (TyTy::BaseType &self,
+                                             HIR::Type &impl_type,
+                                             HIR::Type &trait) const;
+
+  bool validate_type_implements_this (TyTy::BaseType &self,
+                                     HIR::Type &impl_type,
+                                     HIR::Type &trait) const;
+
 private:
   struct mark_is_error
   {
diff --git a/gcc/testsuite/rust/compile/issue-3553.rs 
b/gcc/testsuite/rust/compile/issue-3553.rs
new file mode 100644
index 00000000000..546f3c17bed
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3553.rs
@@ -0,0 +1,18 @@
+trait Foo {
+    fn f(&self) -> isize;
+}
+
+trait Bar: Foo {
+    fn g(&self) -> isize;
+}
+
+struct A {
+    x: isize,
+}
+
+impl Bar for A {
+    // { dg-error "the trait bound .A: Foo. is not satisfied .E0277." "" { 
target *-*-* } .-1 }
+    fn g(&self) -> isize {
+        self.f()
+    }
+}
-- 
2.49.0

Reply via email to