Skip to content

Commit d910e53

Browse files
authored
Rollup merge of #100221 - compiler-errors:impossible-trait-items, r=lcnr,notriddle,camelid
Don't document impossible to call default trait items on impls Closes #100176 This only skips documenting _default_ trait items on impls, not ones that are written inside the impl block. This is a conservative approach, since I think we should document all items written in an impl block (I guess unless hidden or whatever), but the existence of this new query I added makes this easy to extend to other rustdoc cases.
2 parents 7efe24c + b3b23aa commit d910e53

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

Diff for: compiler/rustc_middle/src/query/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,14 @@ rustc_queries! {
19561956
}
19571957
}
19581958

1959+
query is_impossible_method(key: (DefId, DefId)) -> bool {
1960+
desc { |tcx|
1961+
"checking if {} is impossible to call within {}",
1962+
tcx.def_path_str(key.1),
1963+
tcx.def_path_str(key.0),
1964+
}
1965+
}
1966+
19591967
query method_autoderef_steps(
19601968
goal: CanonicalTyGoal<'tcx>
19611969
) -> MethodAutoderefStepsResult<'tcx> {

Diff for: compiler/rustc_trait_selection/src/traits/mod.rs

+76-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ use rustc_infer::traits::TraitEngineExt as _;
3434
use rustc_middle::ty::fold::TypeFoldable;
3535
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
3636
use rustc_middle::ty::visit::TypeVisitable;
37-
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
37+
use rustc_middle::ty::{
38+
self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
39+
VtblEntry,
40+
};
3841
use rustc_span::{sym, Span};
3942
use smallvec::SmallVec;
4043

@@ -503,6 +506,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
503506
result
504507
}
505508

509+
/// Checks whether a trait's method is impossible to call on a given impl.
510+
///
511+
/// This only considers predicates that reference the impl's generics, and not
512+
/// those that reference the method's generics.
513+
fn is_impossible_method<'tcx>(
514+
tcx: TyCtxt<'tcx>,
515+
(impl_def_id, trait_item_def_id): (DefId, DefId),
516+
) -> bool {
517+
struct ReferencesOnlyParentGenerics<'tcx> {
518+
tcx: TyCtxt<'tcx>,
519+
generics: &'tcx ty::Generics,
520+
trait_item_def_id: DefId,
521+
}
522+
impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
523+
type BreakTy = ();
524+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
525+
// If this is a parameter from the trait item's own generics, then bail
526+
if let ty::Param(param) = t.kind()
527+
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
528+
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
529+
{
530+
return ControlFlow::BREAK;
531+
}
532+
t.super_visit_with(self)
533+
}
534+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
535+
if let ty::ReEarlyBound(param) = r.kind()
536+
&& let param_def_id = self.generics.region_param(&param, self.tcx).def_id
537+
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
538+
{
539+
return ControlFlow::BREAK;
540+
}
541+
r.super_visit_with(self)
542+
}
543+
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
544+
if let ty::ConstKind::Param(param) = ct.kind()
545+
&& let param_def_id = self.generics.const_param(&param, self.tcx).def_id
546+
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
547+
{
548+
return ControlFlow::BREAK;
549+
}
550+
ct.super_visit_with(self)
551+
}
552+
}
553+
554+
let generics = tcx.generics_of(trait_item_def_id);
555+
let predicates = tcx.predicates_of(trait_item_def_id);
556+
let impl_trait_ref =
557+
tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
558+
let param_env = tcx.param_env(impl_def_id);
559+
560+
let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
561+
let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
562+
if pred.visit_with(&mut visitor).is_continue() {
563+
Some(Obligation::new(
564+
ObligationCause::dummy_with_span(*span),
565+
param_env,
566+
ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
567+
))
568+
} else {
569+
None
570+
}
571+
});
572+
573+
tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
574+
let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
575+
fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
576+
!fulfill_ctxt.select_all_or_error(infcx).is_empty()
577+
})
578+
}
579+
506580
#[derive(Clone, Debug)]
507581
enum VtblSegment<'tcx> {
508582
MetadataDSA,
@@ -883,6 +957,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
883957
vtable_entries,
884958
vtable_trait_upcasting_coercion_new_vptr_slot,
885959
subst_and_check_impossible_predicates,
960+
is_impossible_method,
886961
try_unify_abstract_consts: |tcx, param_env_and| {
887962
let (param_env, (a, b)) = param_env_and.into_parts();
888963
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)

Diff for: src/librustdoc/html/render/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,15 @@ fn render_impl(
15501550
rendering_params: ImplRenderingParameters,
15511551
) {
15521552
for trait_item in &t.items {
1553+
// Skip over any default trait items that are impossible to call
1554+
// (e.g. if it has a `Self: Sized` bound on an unsized type).
1555+
if let Some(impl_def_id) = parent.item_id.as_def_id()
1556+
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
1557+
&& cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
1558+
{
1559+
continue;
1560+
}
1561+
15531562
let n = trait_item.name;
15541563
if i.items.iter().any(|m| m.name == n) {
15551564
continue;

Diff for: src/test/rustdoc/impossible-default.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![crate_name = "foo"]
2+
3+
// Check that default trait items that are impossible to satisfy
4+
5+
pub trait Foo {
6+
fn needs_sized(&self)
7+
where
8+
Self: Sized,
9+
{}
10+
11+
fn no_needs_sized(&self) {}
12+
}
13+
14+
// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
15+
// "fn needs_sized"
16+
// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
17+
// "fn no_needs_sized"
18+
pub struct Bar([u8]);
19+
20+
impl Foo for Bar {}

0 commit comments

Comments
 (0)