diff options
| author | David Wood <david.wood2@arm.com> | 2025-02-27 00:28:42 +0000 |
|---|---|---|
| committer | David Wood <david.wood2@arm.com> | 2025-06-16 23:04:34 +0000 |
| commit | 9044b78c0dca4751934c249a9d30b1a2d285fb54 (patch) | |
| tree | 769f6f7b3f1d1f61d41c5967e6db4c0fbdf4aa01 | |
| parent | e6238ba7dbdf01445a7691e333c3630d3180f43e (diff) | |
| download | rust-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.
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`. |
