]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Always emit the error highest in the type hierarchy
authorPhilip Herron <herron.philip@googlemail.com>
Tue, 20 May 2025 17:44:57 +0000 (18:44 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:44 +0000 (16:36 +0200)
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.philip@googlemail.com>
gcc/rust/typecheck/rust-coercion.cc
gcc/rust/typecheck/rust-unify.cc
gcc/rust/typecheck/rust-unify.h
gcc/testsuite/rust/compile/traits9.rs
gcc/testsuite/rust/compile/unify-errors1.rs [new file with mode: 0644]

index 3a92a2f2f6ee48f0c3e792cedc006a751e60299b..50c74ed689d3d7a06646c38294e87252c642154c 100644 (file)
@@ -401,7 +401,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;
index 95463ae947347958bf983ad60eff7fa49e2db540..9144f2eafba4af2e2e5949b91298ca8ab8a810dc 100644 (file)
@@ -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 ()
 {
@@ -471,11 +487,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);
@@ -497,11 +510,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);
@@ -609,10 +619,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);
@@ -682,10 +690,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);
@@ -815,10 +821,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)
          {
@@ -877,10 +882,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)
          {
@@ -948,21 +952,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);
@@ -1041,21 +1041,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);
@@ -1072,10 +1068,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);
@@ -1092,10 +1086,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);
@@ -1163,10 +1155,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);
 
@@ -1778,19 +1768,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);
@@ -1842,10 +1830,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);
        }
@@ -1863,10 +1849,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);
     }
index 5ff3b7c48dbe503063ad8e4b4327318a67c3e4b2..f64f0ed27b828b9cd40aaa7cceb3403018adf218 100644 (file)
@@ -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;
index bb3034d0f21cb2007fb496d234b7c3f848b7dce6..f4308e8ccc176cc94d79988aa6e72bbe5dddbc47 100644 (file)
@@ -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 (file)
index 0000000..0fe95ef
--- /dev/null
@@ -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 }
+}