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.
This commit is contained in:
parent
065a1f5df9
commit
717c481739
@ -2724,6 +2724,32 @@ fn note_obligation_cause_code<T>(
|
|||||||
let msg = format!("required by this bound in `{short_item_name}`");
|
let msg = format!("required by this bound in `{short_item_name}`");
|
||||||
multispan.push_span_label(span, msg);
|
multispan.push_span_label(span, msg);
|
||||||
err.span_note(multispan, descr);
|
err.span_note(multispan, descr);
|
||||||
|
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
|
||||||
|
&& let ty::ClauseKind::Trait(trait_pred) = clause
|
||||||
|
{
|
||||||
|
let def_id = trait_pred.def_id();
|
||||||
|
let visible_item = if let Some(local) = def_id.as_local() {
|
||||||
|
// Check for local traits being reachable.
|
||||||
|
let vis = &self.tcx.resolutions(()).effective_visibilities;
|
||||||
|
// Account for non-`pub` traits in the root of the local crate.
|
||||||
|
let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
|
||||||
|
vis.is_reachable(local) || is_locally_reachable
|
||||||
|
} else {
|
||||||
|
// Check for foreign traits being reachable.
|
||||||
|
self.tcx.visible_parent_map(()).get(&def_id).is_some()
|
||||||
|
};
|
||||||
|
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 implelement `{}`, 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)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err.span_note(tcx.def_span(item_def_id), descr);
|
err.span_note(tcx.def_span(item_def_id), descr);
|
||||||
}
|
}
|
||||||
|
19
tests/ui/privacy/sealed-traits/sealed-trait-local.rs
Normal file
19
tests/ui/privacy/sealed-traits/sealed-trait-local.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// provide custom privacy error for sealed traits
|
||||||
|
pub mod a {
|
||||||
|
pub trait Sealed: self::b::Hidden {
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct X;
|
||||||
|
impl Sealed for X {}
|
||||||
|
impl self::b::Hidden for X {}
|
||||||
|
|
||||||
|
mod b {
|
||||||
|
pub trait Hidden {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
impl a::Sealed for S {} //~ ERROR the trait bound `S: Hidden` is not satisfied
|
||||||
|
|
||||||
|
fn main() {}
|
16
tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
Normal file
16
tests/ui/privacy/sealed-traits/sealed-trait-local.stderr
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
error[E0277]: the trait bound `S: Hidden` is not satisfied
|
||||||
|
--> $DIR/sealed-trait-local.rs:17:20
|
||||||
|
|
|
||||||
|
LL | impl a::Sealed for S {}
|
||||||
|
| ^ the trait `Hidden` is not implemented for `S`
|
||||||
|
|
|
||||||
|
note: required by a bound in `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 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
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user