Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't document impossible to call default trait items on impls #100221

Merged
merged 1 commit into from
Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,14 @@ rustc_queries! {
}
}

query is_impossible_method(key: (DefId, DefId)) -> bool {
desc { |tcx|
"checking if {} is impossible to call within {}",
tcx.def_path_str(key.1),
tcx.def_path_str(key.0),
}
}

query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
Expand Down
78 changes: 77 additions & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
use rustc_middle::ty::{
self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
VtblEntry,
};
use rustc_span::{sym, Span};
use smallvec::SmallVec;

Expand Down Expand Up @@ -474,6 +478,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
result
}

/// Checks whether a trait's method is impossible to call on a given impl.
///
/// This only considers predicates that reference the impl's generics, and not
/// those that reference the method's generics.
fn is_impossible_method<'tcx>(
tcx: TyCtxt<'tcx>,
(impl_def_id, trait_item_def_id): (DefId, DefId),
) -> bool {
struct ReferencesOnlyParentGenerics<'tcx> {
tcx: TyCtxt<'tcx>,
generics: &'tcx ty::Generics,
trait_item_def_id: DefId,
}
impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// If this is a parameter from the trait item's own generics, then bail
if let ty::Param(param) = t.kind()
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ReEarlyBound(param) = r.kind()
&& let param_def_id = self.generics.region_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
r.super_visit_with(self)
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Param(param) = ct.kind()
&& let param_def_id = self.generics.const_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
ct.super_visit_with(self)
}
}

let generics = tcx.generics_of(trait_item_def_id);
let predicates = tcx.predicates_of(trait_item_def_id);
let impl_trait_ref =
tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
let param_env = tcx.param_env(impl_def_id);

let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
if pred.visit_with(&mut visitor).is_continue() {
Some(Obligation::new(
ObligationCause::dummy_with_span(*span),
param_env,
ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
))
} else {
None
}
});

tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
!fulfill_ctxt.select_all_or_error(infcx).is_empty()
})
}

#[derive(Clone, Debug)]
enum VtblSegment<'tcx> {
MetadataDSA,
Expand Down Expand Up @@ -854,6 +929,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates,
is_impossible_method,
try_unify_abstract_consts: |tcx, param_env_and| {
let (param_env, (a, b)) = param_env_and.into_parts();
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
Expand Down
9 changes: 9 additions & 0 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,15 @@ fn render_impl(
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
// Skip over any default trait items that are impossible to call
// (e.g. if it has a `Self: Sized` bound on an unsized type).
if let Some(impl_def_id) = parent.item_id.as_def_id()
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
&& cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
{
continue;
}

let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) {
continue;
Expand Down
20 changes: 20 additions & 0 deletions src/test/rustdoc/impossible-default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![crate_name = "foo"]

// Check that default trait items that are impossible to satisfy

pub trait Foo {
fn needs_sized(&self)
where
Self: Sized,
{}

fn no_needs_sized(&self) {}
}

// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
// "fn needs_sized"
// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
// "fn no_needs_sized"
pub struct Bar([u8]);

impl Foo for Bar {}