]> 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)
committerPhilip Herron <philip.herron@embecosm.com>
Tue, 27 May 2025 09:27:15 +0000 (09:27 +0000)
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 f9956b0eeccb50333865924adb5760c56e8c4957..36582de7048333a8d3bbb68f7831aae892682cc5 100644 (file)
@@ -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;
index 219db9a6df9e861e6f3f7dcc474867b7f49df458..e3413a2fea47f967b85f9545f608e60b9c244f1b 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 ()
 {
@@ -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);
     }
index 3d4f625433a480b8a939190e7c45549068c51ae9..4cd121ec782862d34615664fcc5d8cea5cffb9d2 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 }
+}