rustdoc: handle cross-crate RPITITs correctly

This commit is contained in:
León Orell Valerian Liehr 2023-07-22 12:20:17 +02:00
parent c3c5a5c5f7
commit 5924043b86
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
7 changed files with 84 additions and 8 deletions

View File

@ -2081,9 +2081,9 @@ rustc_queries! {
}
}
query is_impossible_method(key: (DefId, DefId)) -> bool {
query is_impossible_associated_item(key: (DefId, DefId)) -> bool {
desc { |tcx|
"checking if `{}` is impossible to call within `{}`",
"checking if `{}` is impossible to reference within `{}`",
tcx.def_path_str(key.1),
tcx.def_path_str(key.0),
}

View File

@ -474,11 +474,14 @@ fn subst_and_check_impossible_predicates<'tcx>(
result
}
/// Checks whether a trait's method is impossible to call on a given impl.
/// Checks whether a trait's associated item is impossible to reference 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: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefId, DefId)) -> bool {
fn is_impossible_associated_item(
tcx: TyCtxt<'_>,
(impl_def_id, trait_item_def_id): (DefId, DefId),
) -> bool {
struct ReferencesOnlyParentGenerics<'tcx> {
tcx: TyCtxt<'tcx>,
generics: &'tcx ty::Generics,
@ -556,7 +559,7 @@ pub fn provide(providers: &mut Providers) {
specializes: specialize::specializes,
subst_and_check_impossible_predicates,
check_tys_might_be_eq: misc::check_tys_might_be_eq,
is_impossible_method,
is_impossible_associated_item,
..*providers
};
}

View File

@ -121,7 +121,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
.tcx
.associated_items(impl_def_id)
.in_definition_order()
.map(|x| clean_middle_assoc_item(x, cx))
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(Box::new(clean_middle_ty(

View File

@ -216,6 +216,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
.tcx
.associated_items(did)
.in_definition_order()
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| clean_middle_assoc_item(item, cx))
.collect();
@ -459,6 +460,7 @@ pub(crate) fn build_impl(
None => (
tcx.associated_items(did)
.in_definition_order()
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
// If this is a trait impl, filter out associated items whose corresponding item
// in the associated trait is marked `doc(hidden)`.

View File

@ -1678,11 +1678,11 @@ fn render_impl(
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
// Skip over any default trait items that are impossible to call
// Skip over any default trait items that are impossible to reference
// (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))
&& cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
{
continue;
}

View File

@ -0,0 +1,35 @@
#![feature(return_position_impl_trait_in_trait)]
pub trait Trait {
fn create() -> impl Iterator<Item = u64> {
std::iter::empty()
}
}
pub struct Basic;
pub struct Intermediate;
pub struct Advanced;
impl Trait for Basic {
// method provided by the trait
}
impl Trait for Intermediate {
fn create() -> std::ops::Range<u64> { // concrete return type
0..1
}
}
impl Trait for Advanced {
fn create() -> impl Iterator<Item = u64> { // opaque return type
std::iter::repeat(0)
}
}
// Regression test for issue #113929:
pub trait Def {
fn def<T>() -> impl Default {}
}
impl Def for () {}

View File

@ -0,0 +1,35 @@
#![crate_name = "user"]
// aux-crate:rpitit=ret-pos-impl-trait-in-trait.rs
// edition:2021
// Test that we can correctly render cross-crate RPITITs.
// In particular, check that we don't render the internal associated type generated by
// their desugaring. We count the number of associated items and ensure that it is exactly one.
// This is more robust than checking for the absence of the associated type.
// @has user/trait.Trait.html
// @has - '//*[@id="method.create"]' 'fn create() -> impl Iterator<Item = u64>'
// The class "method" is used for all three kinds of associated items at the time of writing.
// @count - '//*[@id="main-content"]//section[@class="method"]' 1
pub use rpitit::Trait;
// @has user/struct.Basic.html
// @has - '//*[@id="method.create"]' 'fn create() -> impl Iterator<Item = u64>'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]' 1
pub use rpitit::Basic;
// @has user/struct.Intermediate.html
// @has - '//*[@id="method.create"]' 'fn create() -> Range<u64>'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]' 1
pub use rpitit::Intermediate;
// @has user/struct.Advanced.html
// @has - '//*[@id="method.create"]' 'fn create() -> impl Iterator<Item = u64>'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]' 1
pub use rpitit::Advanced;
// Regression test for issue #113929:
// @has user/trait.Def.html
// @has - '//*[@id="method.def"]' 'fn def<T>() -> impl Default'
pub use rpitit::Def;