Skip to content

Commit 717c481

Browse files
committed
Account for sealed traits in trait bound errors
When implementing a public trait with a private super-trait, we now emit a note that the missing bound is not going to be able to be satisfied, and we explain the concept of a sealed trait.
1 parent 065a1f5 commit 717c481

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

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

+26
Original file line numberDiff line numberDiff line change
@@ -2724,6 +2724,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
27242724
let msg = format!("required by this bound in `{short_item_name}`");
27252725
multispan.push_span_label(span, msg);
27262726
err.span_note(multispan, descr);
2727+
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
2728+
&& let ty::ClauseKind::Trait(trait_pred) = clause
2729+
{
2730+
let def_id = trait_pred.def_id();
2731+
let visible_item = if let Some(local) = def_id.as_local() {
2732+
// Check for local traits being reachable.
2733+
let vis = &self.tcx.resolutions(()).effective_visibilities;
2734+
// Account for non-`pub` traits in the root of the local crate.
2735+
let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
2736+
vis.is_reachable(local) || is_locally_reachable
2737+
} else {
2738+
// Check for foreign traits being reachable.
2739+
self.tcx.visible_parent_map(()).get(&def_id).is_some()
2740+
};
2741+
if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item {
2742+
// FIXME(estebank): extend this to search for all the types that do
2743+
// implement this trait and list them.
2744+
err.note(format!(
2745+
"`{short_item_name}` is a \"sealed trait\", because to implement \
2746+
it you also need to implelement `{}`, which is not accessible; \
2747+
this is usually done to force you to use one of the provided \
2748+
types that already implement it",
2749+
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
2750+
));
2751+
}
2752+
}
27272753
} else {
27282754
err.span_note(tcx.def_span(item_def_id), descr);
27292755
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// provide custom privacy error for sealed traits
2+
pub mod a {
3+
pub trait Sealed: self::b::Hidden {
4+
fn foo() {}
5+
}
6+
7+
struct X;
8+
impl Sealed for X {}
9+
impl self::b::Hidden for X {}
10+
11+
mod b {
12+
pub trait Hidden {}
13+
}
14+
}
15+
16+
struct S;
17+
impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0277]: the trait bound `S: Hidden` is not satisfied
2+
--> $DIR/sealed-trait-local.rs:17:20
3+
|
4+
LL | impl a::Sealed for S {}
5+
| ^ the trait `Hidden` is not implemented for `S`
6+
|
7+
note: required by a bound in `Sealed`
8+
--> $DIR/sealed-trait-local.rs:3:23
9+
|
10+
LL | pub trait Sealed: self::b::Hidden {
11+
| ^^^^^^^^^^^^^^^ required by this bound in `Sealed`
12+
= note: `Sealed` is a "sealed trait", because to implement it you also need to implelement `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+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)