From 6dbad236419075603a616e7b19f585a1a308cf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Oct 2023 16:34:41 +0000 Subject: [PATCH] When encountering sealed traits, point types that implement it ``` error[E0277]: the trait bound `S: d::Hidden` is not satisfied --> $DIR/sealed-trait-local.rs:53:20 | LL | impl c::Sealed for S {} | ^ the trait `d::Hidden` is not implemented for `S` | note: required by a bound in `c::Sealed` --> $DIR/sealed-trait-local.rs:17:23 | LL | pub trait Sealed: self::d::Hidden { | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `c::d::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it = help: the following types implement the trait: - c::X - c::Y ``` The last `help` is new. --- .../src/traits/error_reporting/suggestions.rs | 30 ++++++++++++- .../sealed-traits/sealed-trait-local.rs | 40 ++++++++++++++++- .../sealed-traits/sealed-trait-local.stderr | 44 ++++++++++++++++--- 3 files changed, 105 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 947ea3eece3..aad07d7683a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2691,8 +2691,6 @@ fn note_obligation_cause_code( if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { - // FIXME(estebank): extend this to search for all the types that do - // implement this trait and list them. err.note(format!( "`{short_item_name}` is a \"sealed trait\", because to implement \ it you also need to implement `{}`, which is not accessible; \ @@ -2700,6 +2698,34 @@ fn note_obligation_cause_code( types that already implement it", with_no_trimmed_paths!(tcx.def_path_str(def_id)), )); + let impls_of = tcx.trait_impls_of(def_id); + let impls = impls_of + .non_blanket_impls() + .values() + .flatten() + .chain(impls_of.blanket_impls().iter()) + .collect::>(); + if !impls.is_empty() { + let len = impls.len(); + let mut types = impls.iter() + .map(|t| with_no_trimmed_paths!(format!( + " {}", + tcx.type_of(*t).instantiate_identity(), + ))) + .collect::>(); + let post = if types.len() > 9 { + types.truncate(8); + format!("\nand {} others", len - 8) + } else { + String::new() + }; + err.help(format!( + "the following type{} implement{} the trait:\n{}{post}", + pluralize!(len), + if len == 1 { "s" } else { "" }, + types.join("\n"), + )); + } } } } else { diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.rs b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs index 778ddf0f817..9ae01259a78 100644 --- a/tests/ui/privacy/sealed-traits/sealed-trait-local.rs +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.rs @@ -13,7 +13,43 @@ pub trait Hidden {} } } -struct S; -impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied +pub mod c { + pub trait Sealed: self::d::Hidden { + fn foo() {} + } + struct X; + impl Sealed for X {} + impl self::d::Hidden for X {} + + struct Y; + impl Sealed for Y {} + impl self::d::Hidden for Y {} + + mod d { + pub trait Hidden {} + } +} + +pub mod e { + pub trait Sealed: self::f::Hidden { + fn foo() {} + } + + struct X; + impl self::f::Hidden for X {} + + struct Y; + impl self::f::Hidden for Y {} + impl Sealed for T {} + + mod f { + pub trait Hidden {} + } +} + +struct S; +impl a::Sealed for S {} //~ ERROR the trait bound +impl c::Sealed for S {} //~ ERROR the trait bound +impl e::Sealed for S {} //~ ERROR the trait bound fn main() {} diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr index 5f8076fc84d..a7f77a1c0c0 100644 --- a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr @@ -1,16 +1,50 @@ -error[E0277]: the trait bound `S: Hidden` is not satisfied - --> $DIR/sealed-trait-local.rs:17:20 +error[E0277]: the trait bound `S: b::Hidden` is not satisfied + --> $DIR/sealed-trait-local.rs:52:20 | LL | impl a::Sealed for S {} - | ^ the trait `Hidden` is not implemented for `S` + | ^ the trait `b::Hidden` is not implemented for `S` | -note: required by a bound in `Sealed` +note: required by a bound in `a::Sealed` --> $DIR/sealed-trait-local.rs:3:23 | LL | pub trait Sealed: self::b::Hidden { | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + = help: the following type implements the trait: + a::X -error: aborting due to previous error +error[E0277]: the trait bound `S: d::Hidden` is not satisfied + --> $DIR/sealed-trait-local.rs:53:20 + | +LL | impl c::Sealed for S {} + | ^ the trait `d::Hidden` is not implemented for `S` + | +note: required by a bound in `c::Sealed` + --> $DIR/sealed-trait-local.rs:17:23 + | +LL | pub trait Sealed: self::d::Hidden { + | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` + = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `c::d::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + = help: the following types implement the trait: + c::X + c::Y + +error[E0277]: the trait bound `S: f::Hidden` is not satisfied + --> $DIR/sealed-trait-local.rs:54:20 + | +LL | impl e::Sealed for S {} + | ^ the trait `f::Hidden` is not implemented for `S` + | +note: required by a bound in `e::Sealed` + --> $DIR/sealed-trait-local.rs:35:23 + | +LL | pub trait Sealed: self::f::Hidden { + | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` + = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `e::f::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + = help: the following types implement the trait: + e::X + e::Y + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`.