https://gcc.gnu.org/g:c77c3494f82da01c85a294a5f9c3a0c5496f8572

commit c77c3494f82da01c85a294a5f9c3a0c5496f8572
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Tue May 20 18:44:57 2025 +0100

    gccrs: Always emit the error highest in the type hierarchy
    
    The unify code was a bit dumb here where we always set emit_error to false 
for any
    subtypes for example in comparing tuples we always emitted the whole tuple 
didnt
    match the other tuple but really its much better to say expected bool got 
i32 because
    the element types didn't match.
    
    gcc/rust/ChangeLog:
    
            * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_unsized): 
dont emit error here
            * typecheck/rust-unify.cc (UnifyRules::resolve_subtype): new helper 
to handle emit error
            (UnifyRules::expect_adt): call resolve_subtype
            (UnifyRules::expect_reference): likewise
            (UnifyRules::expect_pointer): likewise
            (UnifyRules::expect_array): likewise
            (UnifyRules::expect_slice): likewise
            (UnifyRules::expect_fndef): likewise
            (UnifyRules::expect_fnptr): likewise
            (UnifyRules::expect_tuple): likewise
            (UnifyRules::expect_closure): likewise
            (UnifyRules::expect_opaque): likeiwse
            * typecheck/rust-unify.h: add new helper to header
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/traits9.rs: update errors
            * rust/compile/unify-errors1.rs: New test.
    
    Signed-off-by: Philip Herron <herron.phi...@googlemail.com>

Diff:
---
 gcc/rust/typecheck/rust-coercion.cc         |   2 +-
 gcc/rust/typecheck/rust-unify.cc            | 128 ++++++++++++----------------
 gcc/rust/typecheck/rust-unify.h             |   3 +
 gcc/testsuite/rust/compile/traits9.rs       |   3 +-
 gcc/testsuite/rust/compile/unify-errors1.rs |  49 +++++++++++
 5 files changed, 110 insertions(+), 75 deletions(-)

diff --git a/gcc/rust/typecheck/rust-coercion.cc 
b/gcc/rust/typecheck/rust-coercion.cc
index f9956b0eeccb..36582de70483 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -393,7 +393,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
 
   if (expect_dyn && need_unsize)
     {
-      bool bounds_compatible = b->bounds_compatible (*a, locus, true);
+      bool bounds_compatible = b->bounds_compatible (*a, locus, false);
       if (!bounds_compatible)
        {
          unsafe_error = true;
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 219db9a6df9e..e3413a2fea47 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -52,6 +52,22 @@ UnifyRules::Resolve (TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
   return result;
 }
 
+TyTy::BaseType *
+UnifyRules::resolve_subtype (TyTy::TyWithLocation lhs, TyTy::TyWithLocation 
rhs)
+{
+  TyTy::BaseType *result
+    = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error, 
infer_flag,
+                          commits, infers);
+
+  // If the recursive call resulted in an error and would have emitted an error
+  // message, disable error emission for the current level to avoid duplicate
+  // errors
+  if (result->get_kind () == TyTy::TypeKind::ERROR && emit_error)
+    emit_error = false;
+
+  return result;
+}
+
 TyTy::BaseType *
 UnifyRules::get_base ()
 {
@@ -463,11 +479,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, 
TyTy::BaseType *rtype)
                TyTy::BaseType *other_field_ty = other_field->get_field_type ();
 
                TyTy::BaseType *unified_ty
-                 = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty),
-                                        TyTy::TyWithLocation (other_field_ty),
-                                        locus, commit_flag,
-                                        false /* emit_error */, infer_flag,
-                                        commits, infers);
+                 = resolve_subtype (TyTy::TyWithLocation (this_field_ty),
+                                    TyTy::TyWithLocation (other_field_ty));
                if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
                  {
                    return new TyTy::ErrorType (0);
@@ -489,11 +502,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, 
TyTy::BaseType *rtype)
                auto pa = a.get_param_ty ();
                auto pb = b.get_param_ty ();
 
-               auto res
-                 = UnifyRules::Resolve (TyTy::TyWithLocation (pa),
-                                        TyTy::TyWithLocation (pb), locus,
-                                        commit_flag, false /* emit_error */,
-                                        infer_flag, commits, infers);
+               auto res = resolve_subtype (TyTy::TyWithLocation (pa),
+                                           TyTy::TyWithLocation (pb));
                if (res->get_kind () == TyTy::TypeKind::ERROR)
                  {
                    return new TyTy::ErrorType (0);
@@ -598,10 +608,8 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, 
TyTy::BaseType *rtype)
        auto other_base_type = type.get_base ();
 
        TyTy::BaseType *base_resolved
-         = UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
-                                TyTy::TyWithLocation (other_base_type), locus,
-                                commit_flag, false /* emit_error */,
-                                infer_flag, commits, infers);
+         = resolve_subtype (TyTy::TyWithLocation (base_type),
+                            TyTy::TyWithLocation (other_base_type));
        if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -669,10 +677,8 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, 
TyTy::BaseType *rtype)
        auto other_base_type = type.get_base ();
 
        TyTy::BaseType *base_resolved
-         = UnifyRules::Resolve (TyTy::TyWithLocation (base_type),
-                                TyTy::TyWithLocation (other_base_type), locus,
-                                commit_flag, false /* emit_error */,
-                                infer_flag, commits, infers);
+         = resolve_subtype (TyTy::TyWithLocation (base_type),
+                            TyTy::TyWithLocation (other_base_type));
        if (base_resolved->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -798,10 +804,9 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, 
TyTy::BaseType *rtype)
 
       case TyTy::ARRAY: {
        TyTy::ArrayType &type = *static_cast<TyTy::ArrayType *> (rtype);
-       TyTy::BaseType *element_unify = UnifyRules::Resolve (
-         TyTy::TyWithLocation (ltype->get_element_type ()),
-         TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
-         false /* emit_error*/, infer_flag, commits, infers);
+       TyTy::BaseType *element_unify
+         = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()),
+                            TyTy::TyWithLocation (type.get_element_type ()));
 
        if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
          {
@@ -858,10 +863,9 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, 
TyTy::BaseType *rtype)
 
       case TyTy::SLICE: {
        TyTy::SliceType &type = *static_cast<TyTy::SliceType *> (rtype);
-       TyTy::BaseType *element_unify = UnifyRules::Resolve (
-         TyTy::TyWithLocation (ltype->get_element_type ()),
-         TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag,
-         false /* emit_error*/, infer_flag, commits, infers);
+       TyTy::BaseType *element_unify
+         = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()),
+                            TyTy::TyWithLocation (type.get_element_type ()));
 
        if (element_unify->get_kind () != TyTy::TypeKind::ERROR)
          {
@@ -927,21 +931,17 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, 
TyTy::BaseType *rtype)
            auto a = ltype->param_at (i).get_type ();
            auto b = type.param_at (i).get_type ();
 
-           auto unified_param
-             = UnifyRules::Resolve (TyTy::TyWithLocation (a),
-                                    TyTy::TyWithLocation (b), locus,
-                                    commit_flag, false /* emit_errors */,
-                                    infer_flag, commits, infers);
+           auto unified_param = resolve_subtype (TyTy::TyWithLocation (a),
+                                                 TyTy::TyWithLocation (b));
            if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
              {
                return new TyTy::ErrorType (0);
              }
          }
 
-       auto unified_return = UnifyRules::Resolve (
-         TyTy::TyWithLocation (ltype->get_return_type ()),
-         TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag,
-         false /* emit_errors */, infer_flag, commits, infers);
+       auto unified_return
+         = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()),
+                            TyTy::TyWithLocation (type.get_return_type ()));
        if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -1018,21 +1018,17 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, 
TyTy::BaseType *rtype)
            auto a = ltype->get_param_type_at (i);
            auto b = type.get_param_type_at (i);
 
-           auto unified_param
-             = UnifyRules::Resolve (TyTy::TyWithLocation (a),
-                                    TyTy::TyWithLocation (b), locus,
-                                    commit_flag, false /* emit_errors */,
-                                    infer_flag, commits, infers);
+           auto unified_param = resolve_subtype (TyTy::TyWithLocation (a),
+                                                 TyTy::TyWithLocation (b));
            if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
              {
                return new TyTy::ErrorType (0);
              }
          }
 
-       auto unified_return = UnifyRules::Resolve (
-         TyTy::TyWithLocation (ltype->get_return_type ()),
-         TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag,
-         false /* emit_errors */, infer_flag, commits, infers);
+       auto unified_return
+         = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()),
+                            TyTy::TyWithLocation (type.get_return_type ()));
        if (unified_return->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -1048,10 +1044,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, 
TyTy::BaseType *rtype)
        auto other_ret_type = type.get_return_type ();
 
        auto unified_result
-         = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type),
-                                TyTy::TyWithLocation (other_ret_type), locus,
-                                commit_flag, false /*emit_errors*/, infer_flag,
-                                commits, infers);
+         = resolve_subtype (TyTy::TyWithLocation (this_ret_type),
+                            TyTy::TyWithLocation (other_ret_type));
        if (unified_result->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -1068,10 +1062,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, 
TyTy::BaseType *rtype)
            auto other_param = type.param_at (i).get_type ();
 
            auto unified_param
-             = UnifyRules::Resolve (TyTy::TyWithLocation (this_param),
-                                    TyTy::TyWithLocation (other_param), locus,
-                                    commit_flag, false /* emit_errors */,
-                                    infer_flag, commits, infers);
+             = resolve_subtype (TyTy::TyWithLocation (this_param),
+                                TyTy::TyWithLocation (other_param));
            if (unified_param->get_kind () == TyTy::TypeKind::ERROR)
              {
                return new TyTy::ErrorType (0);
@@ -1137,10 +1129,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, 
TyTy::BaseType *rtype)
            TyTy::BaseType *fo = type.get_field (i);
 
            TyTy::BaseType *unified_ty
-             = UnifyRules::Resolve (TyTy::TyWithLocation (bo),
-                                    TyTy::TyWithLocation (fo), locus,
-                                    commit_flag, false /* emit_errors */,
-                                    infer_flag, commits, infers);
+             = resolve_subtype (TyTy::TyWithLocation (bo),
+                                TyTy::TyWithLocation (fo));
            if (unified_ty->get_kind () == TyTy::TypeKind::ERROR)
              return new TyTy::ErrorType (0);
 
@@ -1735,19 +1725,17 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, 
TyTy::BaseType *rtype)
            return new TyTy::ErrorType (0);
          }
 
-       TyTy::BaseType *args_res = UnifyRules::Resolve (
-         TyTy::TyWithLocation (&ltype->get_parameters ()),
-         TyTy::TyWithLocation (&type.get_parameters ()), locus, commit_flag,
-         false /* emit_error */, infer_flag, commits, infers);
+       TyTy::BaseType *args_res
+         = resolve_subtype (TyTy::TyWithLocation (&ltype->get_parameters ()),
+                            TyTy::TyWithLocation (&type.get_parameters ()));
        if (args_res->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
          }
 
-       TyTy::BaseType *res = UnifyRules::Resolve (
-         TyTy::TyWithLocation (&ltype->get_result_type ()),
-         TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag,
-         false /* emit_error */, infer_flag, commits, infers);
+       TyTy::BaseType *res
+         = resolve_subtype (TyTy::TyWithLocation (&ltype->get_result_type ()),
+                            TyTy::TyWithLocation (&type.get_result_type ()));
        if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR)
          {
            return new TyTy::ErrorType (0);
@@ -1799,10 +1787,8 @@ UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, 
TyTy::BaseType *rtype)
          auto lr = ltype->resolve ();
          auto rr = ro->resolve ();
 
-         auto res = UnifyRules::Resolve (TyTy::TyWithLocation (lr),
-                                         TyTy::TyWithLocation (rr), locus,
-                                         commit_flag, false /* emit_error */,
-                                         infer_flag, commits, infers);
+         auto res = resolve_subtype (TyTy::TyWithLocation (lr),
+                                     TyTy::TyWithLocation (rr));
          if (res->get_kind () == TyTy::TypeKind::ERROR)
            return new TyTy::ErrorType (0);
        }
@@ -1820,10 +1806,8 @@ UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, 
TyTy::BaseType *rtype)
   else if (ltype->can_resolve ())
     {
       auto underly = ltype->resolve ();
-      auto res = UnifyRules::Resolve (TyTy::TyWithLocation (underly),
-                                     TyTy::TyWithLocation (rtype), locus,
-                                     commit_flag, false /* emit_error */,
-                                     infer_flag, commits, infers);
+      auto res = resolve_subtype (TyTy::TyWithLocation (underly),
+                                 TyTy::TyWithLocation (rtype));
       if (res->get_kind () == TyTy::TypeKind::ERROR)
        return new TyTy::ErrorType (0);
     }
diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h
index 3d4f625433a4..4cd121ec7828 100644
--- a/gcc/rust/typecheck/rust-unify.h
+++ b/gcc/rust/typecheck/rust-unify.h
@@ -91,6 +91,9 @@ private:
              std::vector<CommitSite> &commits,
              std::vector<InferenceSite> &infers);
 
+  TyTy::BaseType *resolve_subtype (TyTy::TyWithLocation lhs,
+                                  TyTy::TyWithLocation rhs);
+
   void emit_type_mismatch () const;
   void emit_abi_mismatch (const TyTy::FnType &expected,
                          const TyTy::FnType &got) const;
diff --git a/gcc/testsuite/rust/compile/traits9.rs 
b/gcc/testsuite/rust/compile/traits9.rs
index bb3034d0f21c..f4308e8ccc17 100644
--- a/gcc/testsuite/rust/compile/traits9.rs
+++ b/gcc/testsuite/rust/compile/traits9.rs
@@ -11,6 +11,5 @@ fn main() {
     a = Foo(123);
 
     let b: &dyn Bar = &a;
-    // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { 
target *-*-* } .-1 }
-    // { dg-error "expected" "" { target *-*-* } .-2 }
+    // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied 
.E0277." "" { target *-*-* } .-1 }
 }
diff --git a/gcc/testsuite/rust/compile/unify-errors1.rs 
b/gcc/testsuite/rust/compile/unify-errors1.rs
new file mode 100644
index 000000000000..0fe95efd0d7f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unify-errors1.rs
@@ -0,0 +1,49 @@
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+trait MyTrait {}
+
+struct Wrapper<T: MyTrait> {
+    value: T,
+}
+
+struct NotImpl;
+
+trait A {}
+trait B {}
+
+struct Wrapper2<T: A + B> {
+    value: T,
+}
+
+struct NotImpl2;
+
+impl A for NotImpl2 {}
+
+fn takes_tuple(x: (i32, bool)) {}
+
+fn requires_copy<T: Copy>(value: T) {}
+
+pub fn test() {
+    takes_tuple((1, 2));
+    // { dg-error "mismatched types, expected .bool. but got .<integer>. 
.E0308." "" { target *-*-* } .-1 }
+
+    takes_tuple((1, 2, 3));
+    // { dg-error "mismatched types, expected ..i32, bool.. but got 
..<integer>, <integer>, <integer>.. .E0308." "" { target *-*-* } .-1 }
+
+    takes_tuple("hello");
+    // { dg-error "mismatched types, expected ..i32, bool.. but got .& str. 
.E0308." "" { target *-*-* } .-1 }
+
+    let x = &mut 5;
+    requires_copy(x);
+    // { dg-error "bounds not satisfied for &mut <integer> .Copy. is not 
satisfied .E0277." "" { target *-*-* } .-1 }
+
+    let _x = Wrapper { value: NotImpl };
+    // { dg-error "bounds not satisfied for NotImpl .MyTrait. is not satisfied 
.E0277." "" { target *-*-* } .-1 }
+
+    let _x = Wrapper2 { value: NotImpl2 };
+    // { dg-error "bounds not satisfied for NotImpl2 .B. is not satisfied 
.E0277." "" { target *-*-* } .-1 }
+}

Reply via email to