Skip to content

Commit db3b02f

Browse files
committed
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.
1 parent cc705b8 commit db3b02f

File tree

3 files changed

+114
-9
lines changed

3 files changed

+114
-9
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -2668,15 +2668,49 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
26682668
if let DefKind::Trait = tcx.def_kind(item_def_id)
26692669
&& !visible_item
26702670
{
2671-
// FIXME(estebank): extend this to search for all the types that do
2672-
// implement this trait and list them.
26732671
err.note(format!(
26742672
"`{short_item_name}` is a \"sealed trait\", because to implement \
26752673
it you also need to implement `{}`, which is not accessible; \
26762674
this is usually done to force you to use one of the provided \
26772675
types that already implement it",
26782676
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
26792677
));
2678+
let impls_of = tcx.trait_impls_of(def_id);
2679+
let impls = impls_of
2680+
.non_blanket_impls()
2681+
.values()
2682+
.flatten()
2683+
.chain(impls_of.blanket_impls().iter())
2684+
.collect::<Vec<_>>();
2685+
match &impls[..] {
2686+
[] => {}
2687+
[only] => {
2688+
err.help(with_no_trimmed_paths!(format!(
2689+
"type `{}` implements the trait",
2690+
tcx.type_of(*only).instantiate_identity(),
2691+
)));
2692+
}
2693+
impls => {
2694+
let mut types = impls.iter()
2695+
.map(|t| with_no_trimmed_paths!(format!(
2696+
" - {}\n",
2697+
tcx.type_of(*t).instantiate_identity(),
2698+
)))
2699+
.collect::<Vec<_>>();
2700+
let post = if types.len() > 9 {
2701+
let len = types.len();
2702+
types.truncate(8);
2703+
format!("and {} others", len - 8)
2704+
} else {
2705+
String::new()
2706+
};
2707+
err.help(format!(
2708+
"the following types implement the trait:\n{}{post}",
2709+
types.join(""),
2710+
));
2711+
}
2712+
}
2713+
26802714
}
26812715
}
26822716
} else {

tests/ui/privacy/sealed-traits/sealed-trait-local.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,43 @@ pub mod a {
1313
}
1414
}
1515

16-
struct S;
17-
impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied
16+
pub mod c {
17+
pub trait Sealed: self::d::Hidden {
18+
fn foo() {}
19+
}
20+
21+
struct X;
22+
impl Sealed for X {}
23+
impl self::d::Hidden for X {}
24+
25+
struct Y;
26+
impl Sealed for Y {}
27+
impl self::d::Hidden for Y {}
28+
29+
mod d {
30+
pub trait Hidden {}
31+
}
32+
}
1833

34+
pub mod e {
35+
pub trait Sealed: self::f::Hidden {
36+
fn foo() {}
37+
}
38+
39+
struct X;
40+
impl self::f::Hidden for X {}
41+
42+
struct Y;
43+
impl self::f::Hidden for Y {}
44+
impl<T: self::f::Hidden> Sealed for T {}
45+
46+
mod f {
47+
pub trait Hidden {}
48+
}
49+
}
50+
51+
struct S;
52+
impl a::Sealed for S {} //~ ERROR the trait bound
53+
impl c::Sealed for S {} //~ ERROR the trait bound
54+
impl e::Sealed for S {} //~ ERROR the trait bound
1955
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,51 @@
1-
error[E0277]: the trait bound `S: Hidden` is not satisfied
2-
--> $DIR/sealed-trait-local.rs:17:20
1+
error[E0277]: the trait bound `S: b::Hidden` is not satisfied
2+
--> $DIR/sealed-trait-local.rs:52:20
33
|
44
LL | impl a::Sealed for S {}
5-
| ^ the trait `Hidden` is not implemented for `S`
5+
| ^ the trait `b::Hidden` is not implemented for `S`
66
|
7-
note: required by a bound in `Sealed`
7+
note: required by a bound in `a::Sealed`
88
--> $DIR/sealed-trait-local.rs:3:23
99
|
1010
LL | pub trait Sealed: self::b::Hidden {
1111
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
1212
= 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
13+
= help: type `a::X` implements the trait
1314

14-
error: aborting due to previous error
15+
error[E0277]: the trait bound `S: d::Hidden` is not satisfied
16+
--> $DIR/sealed-trait-local.rs:53:20
17+
|
18+
LL | impl c::Sealed for S {}
19+
| ^ the trait `d::Hidden` is not implemented for `S`
20+
|
21+
note: required by a bound in `c::Sealed`
22+
--> $DIR/sealed-trait-local.rs:17:23
23+
|
24+
LL | pub trait Sealed: self::d::Hidden {
25+
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
26+
= 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
27+
= help: the following types implement the trait:
28+
- c::X
29+
- c::Y
30+
31+
32+
error[E0277]: the trait bound `S: f::Hidden` is not satisfied
33+
--> $DIR/sealed-trait-local.rs:54:20
34+
|
35+
LL | impl e::Sealed for S {}
36+
| ^ the trait `f::Hidden` is not implemented for `S`
37+
|
38+
note: required by a bound in `e::Sealed`
39+
--> $DIR/sealed-trait-local.rs:35:23
40+
|
41+
LL | pub trait Sealed: self::f::Hidden {
42+
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
43+
= 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
44+
= help: the following types implement the trait:
45+
- e::X
46+
- e::Y
47+
48+
49+
error: aborting due to 3 previous errors
1550

1651
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)