Skip to content

Commit d74b36e

Browse files
committed
Auto merge of #84867 - pnkfelix:rustdoc-revert-deref-recur, r=jyn514
rustdoc: revert deref recur to resume inclusion of impl ExtTrait<Local> for ExtType As discussed here: #82465 (comment), Revert PR #80653 to resolve issue #82465. Issue #82465 was we had stopped including certain trait implementations, namely implementations on an imported type of an imported trait *instantiated on a local type*. That bug was injected by PR #80653. Reverting #80653 means we don't list all the methods that you have accessible via recursively applying `Deref`. [Discussion in last week's rustc triage meeting](https://zulip-archive.rust-lang.org/238009tcompilermeetings/19557weekly2021042954818.html#236680594) led us to conclude that the bug was worse than the enhancement, and there was not an obvious fix for the bug itself. So for the short term we remove the enhancement, while in the long term we will work on figuring out a way to have our imported trait implementation cake and eat it too.
2 parents 539d7bd + b894f75 commit d74b36e

8 files changed

+61
-172
lines changed

src/librustdoc/html/render/context.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::rc::Rc;
66
use std::sync::mpsc::{channel, Receiver};
77

88
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
9-
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
9+
use rustc_hir::def_id::LOCAL_CRATE;
1010
use rustc_middle::ty::TyCtxt;
1111
use rustc_session::Session;
1212
use rustc_span::edition::Edition;
@@ -51,9 +51,6 @@ crate struct Context<'tcx> {
5151
pub(super) render_redirect_pages: bool,
5252
/// The map used to ensure all generated 'id=' attributes are unique.
5353
pub(super) id_map: RefCell<IdMap>,
54-
/// Tracks section IDs for `Deref` targets so they match in both the main
55-
/// body and the sidebar.
56-
pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
5754
/// Shared mutable state.
5855
///
5956
/// Issue for improving the situation: [#82381][]
@@ -74,7 +71,7 @@ crate struct Context<'tcx> {
7471

7572
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
7673
#[cfg(target_arch = "x86_64")]
77-
rustc_data_structures::static_assert_size!(Context<'_>, 152);
74+
rustc_data_structures::static_assert_size!(Context<'_>, 112);
7875

7976
/// Shared mutable state used in [`Context`] and elsewhere.
8077
crate struct SharedContext<'tcx> {
@@ -486,7 +483,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
486483
dst,
487484
render_redirect_pages: false,
488485
id_map: RefCell::new(id_map),
489-
deref_id_map: RefCell::new(FxHashMap::default()),
490486
shared: Rc::new(scx),
491487
cache: Rc::new(cache),
492488
};
@@ -504,7 +500,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
504500
dst: self.dst.clone(),
505501
render_redirect_pages: self.render_redirect_pages,
506502
id_map: RefCell::new(IdMap::new()),
507-
deref_id_map: RefCell::new(FxHashMap::default()),
508503
shared: Rc::clone(&self.shared),
509504
cache: Rc::clone(&self.cache),
510505
}

src/librustdoc/html/render/mod.rs

+6-20
Original file line numberDiff line numberDiff line change
@@ -1045,17 +1045,12 @@ fn render_assoc_items(
10451045
RenderMode::Normal
10461046
}
10471047
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1048-
let id =
1049-
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1050-
debug!("Adding {} to deref id map", type_.print(cx));
1051-
cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
10521048
write!(
10531049
w,
1054-
"<h2 id=\"{id}\" class=\"small-section-header\">\
1050+
"<h2 id=\"deref-methods\" class=\"small-section-header\">\
10551051
Methods from {trait_}&lt;Target = {type_}&gt;\
1056-
<a href=\"#{id}\" class=\"anchor\"></a>\
1052+
<a href=\"#deref-methods\" class=\"anchor\"></a>\
10571053
</h2>",
1058-
id = id,
10591054
trait_ = trait_.print(cx),
10601055
type_ = type_.print(cx),
10611056
);
@@ -1080,6 +1075,9 @@ fn render_assoc_items(
10801075
);
10811076
}
10821077
}
1078+
if let AssocItemRender::DerefFor { .. } = what {
1079+
return;
1080+
}
10831081
if !traits.is_empty() {
10841082
let deref_impl = traits
10851083
.iter()
@@ -1090,13 +1088,6 @@ fn render_assoc_items(
10901088
.any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
10911089
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
10921090
}
1093-
1094-
// If we were already one level into rendering deref methods, we don't want to render
1095-
// anything after recursing into any further deref methods above.
1096-
if let AssocItemRender::DerefFor { .. } = what {
1097-
return;
1098-
}
1099-
11001091
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
11011092
traits.iter().partition(|t| t.inner_impl().synthetic);
11021093
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
@@ -2017,14 +2008,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
20172008
.flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
20182009
.collect::<Vec<_>>();
20192010
if !ret.is_empty() {
2020-
let deref_id_map = cx.deref_id_map.borrow();
2021-
let id = deref_id_map
2022-
.get(&real_target.def_id_full(c).unwrap())
2023-
.expect("Deref section without derived id");
20242011
write!(
20252012
out,
2026-
"<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
2027-
id,
2013+
"<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}&lt;Target={}&gt;</a>",
20282014
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
20292015
Escape(&format!("{:#}", real_target.print(cx))),
20302016
);

src/librustdoc/passes/collect_trait_impls.rs

+35-62
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use crate::clean::*;
33
use crate::core::DocContext;
44
use crate::fold::DocFolder;
55

6-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7-
use rustc_hir::def_id::DefId;
6+
use rustc_data_structures::fx::FxHashSet;
87
use rustc_middle::ty::DefIdTree;
98
use rustc_span::symbol::sym;
109

@@ -53,6 +52,39 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
5352
}
5453
}
5554

55+
let mut cleaner = BadImplStripper { prims, items: crate_items };
56+
57+
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
58+
for it in &new_items {
59+
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
60+
if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
61+
let target = items
62+
.iter()
63+
.find_map(|item| match *item.kind {
64+
TypedefItem(ref t, true) => Some(&t.type_),
65+
_ => None,
66+
})
67+
.expect("Deref impl without Target type");
68+
69+
if let Some(prim) = target.primitive_type() {
70+
cleaner.prims.insert(prim);
71+
} else if let Some(did) = target.def_id() {
72+
cleaner.items.insert(did.into());
73+
}
74+
}
75+
}
76+
}
77+
78+
new_items.retain(|it| {
79+
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
80+
cleaner.keep_impl(for_)
81+
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
82+
|| blanket_impl.is_some()
83+
} else {
84+
true
85+
}
86+
});
87+
5688
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
5789
// doesn't work with it anyway, so pull them from the HIR map instead
5890
let mut extra_attrs = Vec::new();
@@ -84,73 +116,14 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
84116
}
85117
}
86118

87-
let mut cleaner = BadImplStripper { prims, items: crate_items };
88-
89-
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
90-
// Gather all type to `Deref` target edges.
91-
for it in &new_items {
92-
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
93-
if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
94-
let target = items.iter().find_map(|item| match *item.kind {
95-
TypedefItem(ref t, true) => Some(&t.type_),
96-
_ => None,
97-
});
98-
if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
99-
type_did_to_deref_target.insert(for_did, target);
100-
}
101-
}
102-
}
103-
}
104-
// Follow all `Deref` targets of included items and recursively add them as valid
105-
fn add_deref_target(
106-
map: &FxHashMap<DefId, &Type>,
107-
cleaner: &mut BadImplStripper,
108-
type_did: &DefId,
109-
) {
110-
if let Some(target) = map.get(type_did) {
111-
debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
112-
if let Some(target_prim) = target.primitive_type() {
113-
cleaner.prims.insert(target_prim);
114-
} else if let Some(target_did) = target.def_id() {
115-
// `impl Deref<Target = S> for S`
116-
if target_did == *type_did {
117-
// Avoid infinite cycles
118-
return;
119-
}
120-
cleaner.items.insert(target_did.into());
121-
add_deref_target(map, cleaner, &target_did.into());
122-
}
123-
}
124-
}
125-
for type_did in type_did_to_deref_target.keys() {
126-
// Since only the `DefId` portion of the `Type` instances is known to be same for both the
127-
// `Deref` target type and the impl for type positions, this map of types is keyed by
128-
// `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
129-
if cleaner.keep_impl_with_def_id(FakeDefId::Real(*type_did)) {
130-
add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
131-
}
132-
}
133-
134119
let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
135120
items
136121
} else {
137122
panic!("collect-trait-impls can't run");
138123
};
139124

140125
items.extend(synth_impls);
141-
for it in new_items.drain(..) {
142-
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
143-
if !(cleaner.keep_impl(for_)
144-
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
145-
|| blanket_impl.is_some())
146-
{
147-
continue;
148-
}
149-
}
150-
151-
items.push(it);
152-
}
153-
126+
items.extend(new_items);
154127
krate
155128
}
156129

src/test/rustdoc-ui/deref-recursive-cycle.rs

-17
This file was deleted.

src/test/rustdoc/deref-recursive-pathbuf.rs

-24
This file was deleted.

src/test/rustdoc/deref-recursive.rs

-40
This file was deleted.

src/test/rustdoc/deref-typedef.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#![crate_name = "foo"]
22

33
// @has 'foo/struct.Bar.html'
4-
// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
4+
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
55
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
66
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
77
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
88
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
9-
// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
9+
// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
1010
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
1111
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
1212
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::convert::AsRef;
2+
pub struct Local;
3+
4+
// @has issue_82465_asref_for_and_of_local/struct.Local.html '//code' 'impl AsRef<str> for Local'
5+
impl AsRef<str> for Local {
6+
fn as_ref(&self) -> &str {
7+
todo!()
8+
}
9+
}
10+
11+
// @has - '//code' 'impl AsRef<Local> for str'
12+
impl AsRef<Local> for str {
13+
fn as_ref(&self) -> &Local {
14+
todo!()
15+
}
16+
}

0 commit comments

Comments
 (0)