Skip to content

Commit cb882fa

Browse files
committed
Auto merge of #112543 - GuillaumeGomez:revert-112429, r=lcnr
[rustdoc] Fix infinite loop when retrieving impls for type alias Fixes #112515. Reverts #112429. r? `@lcnr`
2 parents fd0a331 + b93ca01 commit cb882fa

File tree

5 files changed

+67
-178
lines changed

5 files changed

+67
-178
lines changed

library/core/src/ptr/mut_ptr.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl<T: ?Sized> *mut T {
106106
/// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit
107107
/// coercion.
108108
///
109-
/// [`cast_mut`]: pointer::cast_mut
109+
/// [`cast_mut`]: #method.cast_mut
110110
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
111111
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
112112
#[inline(always)]
@@ -117,7 +117,7 @@ impl<T: ?Sized> *mut T {
117117
/// Casts a pointer to its raw bits.
118118
///
119119
/// This is equivalent to `as usize`, but is more specific to enhance readability.
120-
/// The inverse method is [`from_bits`](pointer#method.from_bits-1).
120+
/// The inverse method is [`from_bits`](#method.from_bits-1).
121121
///
122122
/// In particular, `*p as usize` and `p as usize` will both compile for
123123
/// pointers to numeric types but do very different things, so using this
@@ -153,7 +153,7 @@ impl<T: ?Sized> *mut T {
153153
/// Creates a pointer from its raw bits.
154154
///
155155
/// This is equivalent to `as *mut T`, but is more specific to enhance readability.
156-
/// The inverse method is [`to_bits`](pointer#method.to_bits-1).
156+
/// The inverse method is [`to_bits`](#method.to_bits-1).
157157
///
158158
/// # Examples
159159
///
@@ -303,7 +303,7 @@ impl<T: ?Sized> *mut T {
303303
///
304304
/// For the mutable counterpart see [`as_mut`].
305305
///
306-
/// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
306+
/// [`as_uninit_ref`]: #method.as_uninit_ref-1
307307
/// [`as_mut`]: #method.as_mut
308308
///
309309
/// # Safety
@@ -369,7 +369,7 @@ impl<T: ?Sized> *mut T {
369369
///
370370
/// For the mutable counterpart see [`as_uninit_mut`].
371371
///
372-
/// [`as_ref`]: pointer#method.as_ref-1
372+
/// [`as_ref`]: #method.as_ref-1
373373
/// [`as_uninit_mut`]: #method.as_uninit_mut
374374
///
375375
/// # Safety
@@ -624,7 +624,7 @@ impl<T: ?Sized> *mut T {
624624
/// For the shared counterpart see [`as_ref`].
625625
///
626626
/// [`as_uninit_mut`]: #method.as_uninit_mut
627-
/// [`as_ref`]: pointer#method.as_ref-1
627+
/// [`as_ref`]: #method.as_ref-1
628628
///
629629
/// # Safety
630630
///
@@ -689,7 +689,7 @@ impl<T: ?Sized> *mut T {
689689
/// For the shared counterpart see [`as_uninit_ref`].
690690
///
691691
/// [`as_mut`]: #method.as_mut
692-
/// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
692+
/// [`as_uninit_ref`]: #method.as_uninit_ref-1
693693
///
694694
/// # Safety
695695
///
@@ -779,7 +779,7 @@ impl<T: ?Sized> *mut T {
779779
///
780780
/// This function is the inverse of [`offset`].
781781
///
782-
/// [`offset`]: pointer#method.offset-1
782+
/// [`offset`]: #method.offset-1
783783
///
784784
/// # Safety
785785
///
@@ -2051,7 +2051,7 @@ impl<T> *mut [T] {
20512051
///
20522052
/// For the mutable counterpart see [`as_uninit_slice_mut`].
20532053
///
2054-
/// [`as_ref`]: pointer#method.as_ref-1
2054+
/// [`as_ref`]: #method.as_ref-1
20552055
/// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut
20562056
///
20572057
/// # Safety

src/librustdoc/html/render/mod.rs

+12-78
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,12 @@ use rustc_data_structures::captures::Captures;
5353
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5454
use rustc_hir::def_id::{DefId, DefIdSet};
5555
use rustc_hir::Mutability;
56-
use rustc_infer::infer::TyCtxtInferExt;
57-
use rustc_infer::traits::{Obligation, ObligationCause};
5856
use rustc_middle::middle::stability;
59-
use rustc_middle::ty::{ParamEnv, TyCtxt};
57+
use rustc_middle::ty::TyCtxt;
6058
use rustc_span::{
6159
symbol::{sym, Symbol},
6260
BytePos, FileName, RealFileName,
6361
};
64-
use rustc_trait_selection::traits::ObligationCtxt;
6562
use serde::ser::{SerializeMap, SerializeSeq};
6663
use serde::{Serialize, Serializer};
6764

@@ -1115,76 +1112,28 @@ fn render_assoc_items<'a, 'cx: 'a>(
11151112
containing_item: &'a clean::Item,
11161113
it: DefId,
11171114
what: AssocItemRender<'a>,
1118-
aliased_type: Option<DefId>,
11191115
) -> impl fmt::Display + 'a + Captures<'cx> {
11201116
let mut derefs = DefIdSet::default();
11211117
derefs.insert(it);
11221118
display_fn(move |f| {
1123-
render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs, aliased_type);
1119+
render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
11241120
Ok(())
11251121
})
11261122
}
11271123

1128-
/// Check whether `impl_def_id` may apply to *some instantiation* of `item_def_id`.
1129-
fn is_valid_impl_for(tcx: TyCtxt<'_>, item_def_id: DefId, impl_def_id: DefId) -> bool {
1130-
let infcx = tcx.infer_ctxt().intercrate(true).build();
1131-
let ocx = ObligationCtxt::new(&infcx);
1132-
let param_env = ParamEnv::empty();
1133-
1134-
let alias_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, item_def_id);
1135-
let alias_ty = tcx.type_of(item_def_id).subst(tcx, alias_substs);
1136-
let alias_bounds = tcx.predicates_of(item_def_id).instantiate(tcx, alias_substs);
1137-
1138-
let impl_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, impl_def_id);
1139-
let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
1140-
let impl_bounds = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
1141-
1142-
if ocx.eq(&ObligationCause::dummy(), param_env, impl_self_ty, alias_ty).is_err() {
1143-
return false;
1144-
}
1145-
ocx.register_obligations(
1146-
alias_bounds
1147-
.iter()
1148-
.chain(impl_bounds)
1149-
.map(|(p, _)| Obligation::new(tcx, ObligationCause::dummy(), param_env, p)),
1150-
);
1151-
1152-
let errors = ocx.select_where_possible();
1153-
errors.is_empty()
1154-
}
1155-
1156-
// If `aliased_type` is `Some`, it means `it` is a type alias and `aliased_type` is the "actual"
1157-
// type aliased behind `it`. It is used to check whether or not the implementation of the aliased
1158-
// type can be displayed on the alias doc page.
11591124
fn render_assoc_items_inner(
11601125
mut w: &mut dyn fmt::Write,
11611126
cx: &mut Context<'_>,
11621127
containing_item: &clean::Item,
11631128
it: DefId,
11641129
what: AssocItemRender<'_>,
11651130
derefs: &mut DefIdSet,
1166-
aliased_type: Option<DefId>,
11671131
) {
11681132
info!("Documenting associated items of {:?}", containing_item.name);
11691133
let shared = Rc::clone(&cx.shared);
11701134
let cache = &shared.cache;
1171-
let empty = Vec::new();
1172-
let v = match cache.impls.get(&it) {
1173-
Some(v) => v,
1174-
None => &empty,
1175-
};
1176-
let v2 = match aliased_type {
1177-
Some(aliased_type) => cache.impls.get(&aliased_type).unwrap_or(&empty),
1178-
None => &empty,
1179-
};
1180-
if v.is_empty() && v2.is_empty() {
1181-
return;
1182-
}
1183-
let mut saw_impls = FxHashSet::default();
1184-
let (non_trait, traits): (Vec<_>, _) =
1185-
v.iter().chain(v2).partition(|i| i.inner_impl().trait_.is_none());
1186-
let tcx = cx.tcx();
1187-
let is_alias = aliased_type.is_some();
1135+
let Some(v) = cache.impls.get(&it) else { return };
1136+
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
11881137
if !non_trait.is_empty() {
11891138
let mut tmp_buf = Buffer::html();
11901139
let (render_mode, id, class_html) = match what {
@@ -1216,12 +1165,6 @@ fn render_assoc_items_inner(
12161165
};
12171166
let mut impls_buf = Buffer::html();
12181167
for i in &non_trait {
1219-
if !saw_impls.insert(i.def_id()) {
1220-
continue;
1221-
}
1222-
if is_alias && !is_valid_impl_for(tcx, it, i.def_id()) {
1223-
continue;
1224-
}
12251168
render_impl(
12261169
&mut impls_buf,
12271170
cx,
@@ -1250,14 +1193,9 @@ fn render_assoc_items_inner(
12501193
if !traits.is_empty() {
12511194
let deref_impl =
12521195
traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
1253-
if let Some(impl_) = deref_impl &&
1254-
(!is_alias || is_valid_impl_for(tcx, it, impl_.def_id()))
1255-
{
1196+
if let Some(impl_) = deref_impl {
12561197
let has_deref_mut =
1257-
traits.iter().any(|t| {
1258-
t.trait_did() == cx.tcx().lang_items().deref_mut_trait() &&
1259-
(!is_alias || is_valid_impl_for(tcx, it, t.def_id()))
1260-
});
1198+
traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
12611199
render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs);
12621200
}
12631201

@@ -1267,14 +1205,10 @@ fn render_assoc_items_inner(
12671205
return;
12681206
}
12691207

1270-
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits
1271-
.into_iter()
1272-
.filter(|t| saw_impls.insert(t.def_id()))
1273-
.partition(|t| t.inner_impl().kind.is_auto());
1274-
let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete
1275-
.into_iter()
1276-
.filter(|t| !is_alias || is_valid_impl_for(tcx, it, t.def_id()))
1277-
.partition(|t| t.inner_impl().kind.is_blanket());
1208+
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1209+
traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1210+
let (blanket_impl, concrete): (Vec<&Impl>, _) =
1211+
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
12781212

12791213
render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
12801214
}
@@ -1313,10 +1247,10 @@ fn render_deref_methods(
13131247
return;
13141248
}
13151249
}
1316-
render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None);
1250+
render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
13171251
} else if let Some(prim) = target.primitive_type() {
13181252
if let Some(&did) = cache.primitive_locations.get(&prim) {
1319-
render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None);
1253+
render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
13201254
}
13211255
}
13221256
}

src/librustdoc/html/render/print_item.rs

+16-32
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ macro_rules! item_template_methods {
129129
display_fn(move |f| {
130130
let (item, mut cx) = self.item_and_mut_cx();
131131
let def_id = item.item_id.expect_def_id();
132-
let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All, None);
132+
let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All);
133133
write!(f, "{v}")
134134
})
135135
}
@@ -953,11 +953,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
953953
}
954954

955955
// If there are methods directly on this trait object, render them here.
956-
write!(
957-
w,
958-
"{}",
959-
render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None)
960-
);
956+
write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All));
961957

962958
let cloned_shared = Rc::clone(&cx.shared);
963959
let cache = &cloned_shared.cache;
@@ -1189,12 +1185,8 @@ fn item_trait_alias(
11891185
// won't be visible anywhere in the docs. It would be nice to also show
11901186
// associated items from the aliased type (see discussion in #32077), but
11911187
// we need #14072 to make sense of the generics.
1192-
write!(
1193-
w,
1194-
"{}",
1195-
render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None)
1196-
)
1197-
.unwrap();
1188+
write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
1189+
.unwrap();
11981190
}
11991191

12001192
fn item_opaque_ty(
@@ -1222,12 +1214,8 @@ fn item_opaque_ty(
12221214
// won't be visible anywhere in the docs. It would be nice to also show
12231215
// associated items from the aliased type (see discussion in #32077), but
12241216
// we need #14072 to make sense of the generics.
1225-
write!(
1226-
w,
1227-
"{}",
1228-
render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None)
1229-
)
1230-
.unwrap();
1217+
write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
1218+
.unwrap();
12311219
}
12321220

12331221
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
12511239
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
12521240

12531241
let def_id = it.item_id.expect_def_id();
1254-
write!(
1255-
w,
1256-
"{}",
1257-
render_assoc_items(cx, it, def_id, AssocItemRender::All, t.type_.def_id(&cx.cache()))
1258-
);
1242+
// Render any items associated directly to this alias, as otherwise they
1243+
// won't be visible anywhere in the docs. It would be nice to also show
1244+
// associated items from the aliased type (see discussion in #32077), but
1245+
// we need #14072 to make sense of the generics.
1246+
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
12591247
write!(w, "{}", document_type_layout(cx, def_id));
12601248
}
12611249

@@ -1494,7 +1482,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
14941482
write!(w, "</div>");
14951483
}
14961484
let def_id = it.item_id.expect_def_id();
1497-
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None));
1485+
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
14981486
write!(w, "{}", document_type_layout(cx, def_id));
14991487
}
15001488

@@ -1537,7 +1525,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite
15371525
let def_id = it.item_id.expect_def_id();
15381526
write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
15391527
if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
1540-
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None)).unwrap();
1528+
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)).unwrap();
15411529
} else {
15421530
// We handle the "reference" primitive type on its own because we only want to list
15431531
// implementations on generic types.
@@ -1642,7 +1630,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
16421630
}
16431631
}
16441632
let def_id = it.item_id.expect_def_id();
1645-
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All, None));
1633+
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
16461634
write!(w, "{}", document_type_layout(cx, def_id));
16471635
}
16481636

@@ -1677,12 +1665,8 @@ fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::
16771665
});
16781666

16791667
write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
1680-
write!(
1681-
w,
1682-
"{}",
1683-
render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All, None)
1684-
)
1685-
.unwrap();
1668+
write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
1669+
.unwrap();
16861670
}
16871671

16881672
fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Regression test for <https://github.com/rust-lang/rust/issues/112515>.
2+
// It's to ensure that this code doesn't have infinite loop in rustdoc when
3+
// trying to retrive type alias implementations.
4+
5+
// ignore-tidy-linelength
6+
7+
pub type Boom = S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<u64, u8>, ()>, ()>, ()>, u8>, ()>, u8>, ()>, u8>, u8>, ()>, ()>, ()>, u8>, u8>, u8>, ()>, ()>, u8>, ()>, ()>, ()>, u8>, u8>, ()>, ()>, ()>, ()>, ()>, u8>, ()>, ()>, u8>, ()>, ()>, ()>, u8>, ()>, ()>, u8>, u8>, u8>, u8>, ()>, u8>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>, ()>;
8+
pub struct S<T, U>(T, U);
9+
10+
pub trait A {}
11+
12+
pub trait B<T> {
13+
type P;
14+
}
15+
16+
impl A for u64 {}
17+
18+
impl<T, U> A for S<T, U> {}
19+
20+
impl<T> B<u8> for S<T, ()>
21+
where
22+
T: B<u8>,
23+
<T as B<u8>>::P: A,
24+
{
25+
type P = ();
26+
}
27+
28+
impl<T: A, U, V> B<T> for S<U, V> {
29+
type P = ();
30+
}

0 commit comments

Comments
 (0)