From: Philip Herron <[email protected]>
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 <[email protected]>
---
.../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