diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index e753647ff7868..c6f43857887c9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -106,7 +106,7 @@ impl *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: pointer::cast_mut + /// [`cast_mut`]: #method.cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[inline(always)] @@ -117,7 +117,7 @@ impl *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](pointer#method.from_bits-1). + /// The inverse method is [`from_bits`](#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -153,7 +153,7 @@ impl *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](pointer#method.to_bits-1). + /// The inverse method is [`to_bits`](#method.to_bits-1). /// /// # Examples /// @@ -303,7 +303,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 + /// [`as_uninit_ref`]: #method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -369,7 +369,7 @@ impl *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -624,7 +624,7 @@ impl *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// /// # Safety /// @@ -689,7 +689,7 @@ impl *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 + /// [`as_uninit_ref`]: #method.as_uninit_ref-1 /// /// # Safety /// @@ -779,7 +779,7 @@ impl *mut T { /// /// This function is the inverse of [`offset`]. /// - /// [`offset`]: pointer#method.offset-1 + /// [`offset`]: #method.offset-1 /// /// # Safety /// @@ -2051,7 +2051,7 @@ impl *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: pointer#method.as_ref-1 + /// [`as_ref`]: #method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index baffee0964da9..f205ff15ec3d0 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -53,15 +53,12 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::middle::stability; -use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_span::{ symbol::{sym, Symbol}, BytePos, FileName, RealFileName, }; -use rustc_trait_selection::traits::ObligationCtxt; use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; @@ -1115,47 +1112,15 @@ fn render_assoc_items<'a, 'cx: 'a>( containing_item: &'a clean::Item, it: DefId, what: AssocItemRender<'a>, - aliased_type: Option, ) -> impl fmt::Display + 'a + Captures<'cx> { let mut derefs = DefIdSet::default(); derefs.insert(it); display_fn(move |f| { - render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs, aliased_type); + render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); Ok(()) }) } -/// Check whether `impl_def_id` may apply to *some instantiation* of `item_def_id`. -fn is_valid_impl_for(tcx: TyCtxt<'_>, item_def_id: DefId, impl_def_id: DefId) -> bool { - let infcx = tcx.infer_ctxt().intercrate(true).build(); - let ocx = ObligationCtxt::new(&infcx); - let param_env = ParamEnv::empty(); - - let alias_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, item_def_id); - let alias_ty = tcx.type_of(item_def_id).subst(tcx, alias_substs); - let alias_bounds = tcx.predicates_of(item_def_id).instantiate(tcx, alias_substs); - - let impl_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, impl_def_id); - let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs); - let impl_bounds = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs); - - if ocx.eq(&ObligationCause::dummy(), param_env, impl_self_ty, alias_ty).is_err() { - return false; - } - ocx.register_obligations( - alias_bounds - .iter() - .chain(impl_bounds) - .map(|(p, _)| Obligation::new(tcx, ObligationCause::dummy(), param_env, p)), - ); - - let errors = ocx.select_where_possible(); - errors.is_empty() -} - -// If `aliased_type` is `Some`, it means `it` is a type alias and `aliased_type` is the "actual" -// type aliased behind `it`. It is used to check whether or not the implementation of the aliased -// type can be displayed on the alias doc page. fn render_assoc_items_inner( mut w: &mut dyn fmt::Write, cx: &mut Context<'_>, @@ -1163,28 +1128,12 @@ fn render_assoc_items_inner( it: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, - aliased_type: Option, ) { info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); let cache = &shared.cache; - let empty = Vec::new(); - let v = match cache.impls.get(&it) { - Some(v) => v, - None => &empty, - }; - let v2 = match aliased_type { - Some(aliased_type) => cache.impls.get(&aliased_type).unwrap_or(&empty), - None => &empty, - }; - if v.is_empty() && v2.is_empty() { - return; - } - let mut saw_impls = FxHashSet::default(); - let (non_trait, traits): (Vec<_>, _) = - v.iter().chain(v2).partition(|i| i.inner_impl().trait_.is_none()); - let tcx = cx.tcx(); - let is_alias = aliased_type.is_some(); + let Some(v) = cache.impls.get(&it) else { return }; + let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1216,12 +1165,6 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { - if !saw_impls.insert(i.def_id()) { - continue; - } - if is_alias && !is_valid_impl_for(tcx, it, i.def_id()) { - continue; - } render_impl( &mut impls_buf, cx, @@ -1250,14 +1193,9 @@ fn render_assoc_items_inner( if !traits.is_empty() { let deref_impl = traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait()); - if let Some(impl_) = deref_impl && - (!is_alias || is_valid_impl_for(tcx, it, impl_.def_id())) - { + if let Some(impl_) = deref_impl { let has_deref_mut = - traits.iter().any(|t| { - t.trait_did() == cx.tcx().lang_items().deref_mut_trait() && - (!is_alias || is_valid_impl_for(tcx, it, t.def_id())) - }); + traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait()); render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs); } @@ -1267,14 +1205,10 @@ fn render_assoc_items_inner( return; } - let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits - .into_iter() - .filter(|t| saw_impls.insert(t.def_id())) - .partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete - .into_iter() - .filter(|t| !is_alias || is_valid_impl_for(tcx, it, t.def_id())) - .partition(|t| t.inner_impl().kind.is_blanket()); + let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = + traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = + concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } @@ -1313,10 +1247,10 @@ fn render_deref_methods( return; } } - render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); } else if let Some(prim) = target.primitive_type() { if let Some(&did) = cache.primitive_locations.get(&prim) { - render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); } } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 02cfad6b34679..383e3c170881a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -129,7 +129,7 @@ macro_rules! item_template_methods { display_fn(move |f| { let (item, mut cx) = self.item_and_mut_cx(); let def_id = item.item_id.expect_def_id(); - let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All, None); + let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All); write!(f, "{v}") }) } @@ -953,11 +953,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } // If there are methods directly on this trait object, render them here. - write!( - w, - "{}", - render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None) - ); + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)); let cloned_shared = Rc::clone(&cx.shared); let cache = &cloned_shared.cache; @@ -1189,12 +1185,8 @@ fn item_trait_alias( // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - write!( - w, - "{}", - render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None) - ) - .unwrap(); + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) + .unwrap(); } fn item_opaque_ty( @@ -1222,12 +1214,8 @@ fn item_opaque_ty( // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - write!( - w, - "{}", - render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None) - ) - .unwrap(); + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) + .unwrap(); } fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) { @@ -1251,11 +1239,11 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); let def_id = it.item_id.expect_def_id(); - write!( - w, - "{}", - render_assoc_items(cx, it, def_id, AssocItemRender::All, t.type_.def_id(&cx.cache())) - ); + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); } @@ -1494,7 +1482,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!(w, ""); } let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None)); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); } @@ -1537,7 +1525,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite let def_id = it.item_id.expect_def_id(); write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None)).unwrap(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)).unwrap(); } else { // We handle the "reference" primitive type on its own because we only want to list // implementations on generic types. @@ -1642,7 +1630,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } } let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None)); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); } @@ -1677,12 +1665,8 @@ fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean:: }); write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); - write!( - w, - "{}", - render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None) - ) - .unwrap(); + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) + .unwrap(); } fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { diff --git a/tests/rustdoc/issue-112515-impl-ty-alias.rs b/tests/rustdoc/issue-112515-impl-ty-alias.rs new file mode 100644 index 0000000000000..161188ee5762f --- /dev/null +++ b/tests/rustdoc/issue-112515-impl-ty-alias.rs @@ -0,0 +1,30 @@ +// Regression test for . +// It's to ensure that this code doesn't have infinite loop in rustdoc when +// trying to retrive type alias implementations. + +// ignore-tidy-linelength + +pub type Boom = S, ()>, ()>, ()>, u8>, ()>, u8>, ()>, u8>, u8>, ()>, ()>, ()>, u8>, u8>, u8>, ()>, ()>, u8>, ()>, ()>, ()>, u8>, u8>, ()>, ()>, ()>, ()>, ()>, u8>, ()>, ()>, u8>, ()>, ()>, ()>, u8>, ()>, ()>, u8>, u8>, u8>, u8>, ()>, u8>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>; +pub struct S(T, U); + +pub trait A {} + +pub trait B { + type P; +} + +impl A for u64 {} + +impl A for S {} + +impl B for S +where + T: B, + >::P: A, +{ + type P = (); +} + +impl B for S { + type P = (); +} diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs deleted file mode 100644 index 555d0579bee79..0000000000000 --- a/tests/rustdoc/issue-32077-type-alias-impls.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Regression test for . - -#![crate_name = "foo"] - -pub struct GenericStruct(T); - -impl GenericStruct { - pub fn on_gen(arg: T) {} -} - -impl GenericStruct { - pub fn on_u32(arg: u32) {} -} - -pub trait Foo {} -pub trait Bar {} - -impl Foo for GenericStruct {} -impl Bar for GenericStruct {} - -// @has 'foo/type.TypedefStruct.html' -// We check that we have the implementation of the type alias itself. -// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' -// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' -// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl GenericStruct' -// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' -// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl Foo for GenericStruct' -// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. -// @!has - '//h3' 'impl Bar for GenericStruct {}' -// Same goes for the `Deref` impl. -// @!has - '//h2' 'Methods from Deref' -pub type TypedefStruct = GenericStruct; - -impl TypedefStruct { - pub fn on_alias() {} -} - -impl std::ops::Deref for GenericStruct { - type Target = u32; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub struct Wrap(GenericStruct); - -// @has 'foo/type.Alias.html' -// @has - '//h2' 'Methods from Deref' -// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl Deref for Wrap' -pub type Alias = Wrap; - -impl std::ops::Deref for Wrap { - type Target = GenericStruct; - - fn deref(&self) -> &Self::Target { - &self.0 - } -}