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