Skip to content

Commit

Permalink
Rollup merge of rust-lang#116945 - estebank:sealed-trait-impls, r=pet…
Browse files Browse the repository at this point in the history
…rochenkov

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.
  • Loading branch information
matthiaskrgr authored Oct 28, 2023
2 parents d03d191 + 6dbad23 commit b9b21c1
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2691,15 +2691,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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; \
this is usually done to force you to use one of the provided \
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::<Vec<_>>();
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::<Vec<_>>();
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 {
Expand Down
40 changes: 38 additions & 2 deletions tests/ui/privacy/sealed-traits/sealed-trait-local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,43 @@ pub mod a {
}
}

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<T: self::f::Hidden> 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() {}
44 changes: 39 additions & 5 deletions tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit b9b21c1

Please sign in to comment.