about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood2@arm.com>2025-02-27 00:28:42 +0000
committerDavid Wood <david.wood2@arm.com>2025-06-16 23:04:34 +0000
commit9044b78c0dca4751934c249a9d30b1a2d285fb54 (patch)
tree769f6f7b3f1d1f61d41c5967e6db4c0fbdf4aa01
parente6238ba7dbdf01445a7691e333c3630d3180f43e (diff)
downloadrust-9044b78c0dca4751934c249a9d30b1a2d285fb54.tar.gz
rust-9044b78c0dca4751934c249a9d30b1a2d285fb54.zip
trait_sel: print `{Meta,Pointee}Sized` impl headers
When printing impl headers in a diagnostic, the compiler has to account
for `?Sized` implying `MetaSized` and new `MetaSized` and `PointeeSized`
bounds.
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs62
-rw-r--r--tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs19
-rw-r--r--tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs7
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs26
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr42
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat.rs19
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat.stderr22
-rw-r--r--tests/ui/sized-hierarchy/pretty-print.rs28
-rw-r--r--tests/ui/sized-hierarchy/pretty-print.stderr43
9 files changed, 252 insertions, 16 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index d6f12524304..edca264733b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, AmbigArg, LangItem};
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_infer::traits::solve::Goal;
 use rustc_infer::traits::{
     DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
@@ -334,19 +334,26 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
     let mut w = "impl".to_owned();
 
-    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
+    #[derive(Debug, Default)]
+    struct SizednessFound {
+        sized: bool,
+        meta_sized: bool,
+    }
 
-    // FIXME: Currently only handles ?Sized.
-    //        Needs to support ?Move and ?DynSized when they are implemented.
-    let mut types_without_default_bounds = FxIndexSet::default();
-    let sized_trait = tcx.lang_items().sized_trait();
+    let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
+
+    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
 
     let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
     if !arg_names.is_empty() {
-        types_without_default_bounds.extend(args.types());
         w.push('<');
         w.push_str(&arg_names.join(", "));
         w.push('>');
+
+        for ty in args.types() {
+            // `PointeeSized` params might have no predicates.
+            types_with_sizedness_bounds.insert(ty, SizednessFound::default());
+        }
     }
 
     write!(
@@ -358,24 +365,47 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     )
     .unwrap();
 
-    // The predicates will contain default bounds like `T: Sized`. We need to
-    // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
     let predicates = tcx.predicates_of(impl_def_id).predicates;
-    let mut pretty_predicates =
-        Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
+    let mut pretty_predicates = Vec::with_capacity(predicates.len());
+
+    let sized_trait = tcx.lang_items().sized_trait();
+    let meta_sized_trait = tcx.lang_items().meta_sized_trait();
 
     for (p, _) in predicates {
-        if let Some(poly_trait_ref) = p.as_trait_clause() {
-            if Some(poly_trait_ref.def_id()) == sized_trait {
-                // FIXME(#120456) - is `swap_remove` correct?
-                types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
+        // Accumulate the sizedness bounds for each self ty.
+        if let Some(trait_clause) = p.as_trait_clause() {
+            let self_ty = trait_clause.self_ty().skip_binder();
+            let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
+            if Some(trait_clause.def_id()) == sized_trait {
+                sizedness_of.sized = true;
+                continue;
+            } else if Some(trait_clause.def_id()) == meta_sized_trait {
+                sizedness_of.meta_sized = true;
                 continue;
             }
         }
+
         pretty_predicates.push(p.to_string());
     }
 
-    pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
+    for (ty, sizedness) in types_with_sizedness_bounds {
+        if !tcx.features().sized_hierarchy() {
+            if sizedness.sized {
+                // Maybe a default bound, don't write anything.
+            } else {
+                pretty_predicates.push(format!("{ty}: ?Sized"));
+            }
+        } else {
+            if sizedness.sized {
+                // Maybe a default bound, don't write anything.
+                pretty_predicates.push(format!("{ty}: Sized"));
+            } else if sizedness.meta_sized {
+                pretty_predicates.push(format!("{ty}: MetaSized"));
+            } else {
+                pretty_predicates.push(format!("{ty}: PointeeSized"));
+            }
+        }
+    }
 
     if !pretty_predicates.is_empty() {
         write!(w, "\n  where {}", pretty_predicates.join(", ")).unwrap();
diff --git a/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs b/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs
new file mode 100644
index 00000000000..a7d18d90368
--- /dev/null
+++ b/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs
@@ -0,0 +1,19 @@
+#![feature(sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+pub trait SizedTr {}
+
+impl<T: Sized> SizedTr for T {}
+
+pub trait NegSizedTr {}
+
+impl<T: ?Sized> NegSizedTr for T {}
+
+pub trait MetaSizedTr {}
+
+impl<T: MetaSized> MetaSizedTr for T {}
+
+pub trait PointeeSizedTr: PointeeSized {}
+
+impl<T: PointeeSized> PointeeSizedTr for T {}
diff --git a/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs b/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs
new file mode 100644
index 00000000000..3314b0f356f
--- /dev/null
+++ b/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs
@@ -0,0 +1,7 @@
+pub trait SizedTr {}
+
+impl<T: Sized> SizedTr for T {}
+
+pub trait NegSizedTr {}
+
+impl<T: ?Sized> NegSizedTr for T {}
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs
new file mode 100644
index 00000000000..0412ff651ce
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs
@@ -0,0 +1,26 @@
+//@ aux-build:pretty-print-dep.rs
+//@ compile-flags: --crate-type=lib
+
+extern crate pretty_print_dep;
+use pretty_print_dep::{SizedTr, NegSizedTr, MetaSizedTr, PointeeSizedTr};
+
+// Test that printing the sizedness trait bounds in the conflicting impl error without enabling
+// `sized_hierarchy` will continue to print `?Sized`, even if the dependency is compiled with
+// `sized_hierarchy`.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
+
+impl<T: ?Sized> MetaSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+
+impl<T: ?Sized> PointeeSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr
new file mode 100644
index 00000000000..cb9bfd178f8
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr
@@ -0,0 +1,42 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:16:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> SizedTr for T;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:19:1
+   |
+LL | impl<T: ?Sized> NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> NegSizedTr for T
+             where T: ?Sized;
+
+error[E0119]: conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:22:1
+   |
+LL | impl<T: ?Sized> MetaSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> MetaSizedTr for T
+             where T: ?Sized;
+
+error[E0119]: conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:25:1
+   |
+LL | impl<T: ?Sized> PointeeSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> PointeeSizedTr for T
+             where T: ?Sized;
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat.rs b/tests/ui/sized-hierarchy/pretty-print-no-feat.rs
new file mode 100644
index 00000000000..d5800be5828
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat.rs
@@ -0,0 +1,19 @@
+//@ aux-build:pretty-print-no-feat-dep.rs
+//@ compile-flags: --crate-type=lib
+
+extern crate pretty_print_no_feat_dep;
+use pretty_print_no_feat_dep::{SizedTr, NegSizedTr};
+
+// Test that printing the sizedness trait bounds in the conflicting impl error without enabling
+// `sized_hierarchy` will continue to print `?Sized`.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr b/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr
new file mode 100644
index 00000000000..1d50f0145fe
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr
@@ -0,0 +1,22 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat.rs:15:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_no_feat_dep`:
+           - impl<T> SizedTr for T;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat.rs:18:1
+   |
+LL | impl<T: ?Sized> NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_no_feat_dep`:
+           - impl<T> NegSizedTr for T
+             where T: ?Sized;
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/sized-hierarchy/pretty-print.rs b/tests/ui/sized-hierarchy/pretty-print.rs
new file mode 100644
index 00000000000..0908e76490c
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print.rs
@@ -0,0 +1,28 @@
+//@ aux-build:pretty-print-dep.rs
+//@ compile-flags: --crate-type=lib
+#![feature(sized_hierarchy)]
+
+// Test that printing the sizedness trait bounds in the conflicting impl error with
+// `sized_hierarchy` enabled prints all of the appropriate bounds.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+use std::marker::{MetaSized, PointeeSized};
+
+extern crate pretty_print_dep;
+use pretty_print_dep::{SizedTr, MetaSizedTr, PointeeSizedTr};
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
+
+impl<T: MetaSized> MetaSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+
+impl<T: PointeeSized> PointeeSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print.stderr b/tests/ui/sized-hierarchy/pretty-print.stderr
new file mode 100644
index 00000000000..3602c804945
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print.stderr
@@ -0,0 +1,43 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:18:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> SizedTr for T
+             where T: Sized;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:21:1
+   |
+LL | impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> NegSizedTr for T
+             where T: MetaSized;
+
+error[E0119]: conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:24:1
+   |
+LL | impl<T: MetaSized> MetaSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> MetaSizedTr for T
+             where T: MetaSized;
+
+error[E0119]: conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:27:1
+   |
+LL | impl<T: PointeeSized> PointeeSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> PointeeSizedTr for T
+             where T: PointeeSized;
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0119`.