Skip to content

Commit 12a95b0

Browse files
authored
Rollup 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 cfa2c21 + 86e3f76 commit 12a95b0

File tree

8 files changed

+62
-176
lines changed

8 files changed

+62
-176
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;
@@ -50,9 +50,6 @@ crate struct Context<'tcx> {
5050
pub(super) render_redirect_pages: bool,
5151
/// The map used to ensure all generated 'id=' attributes are unique.
5252
pub(super) id_map: RefCell<IdMap>,
53-
/// Tracks section IDs for `Deref` targets so they match in both the main
54-
/// body and the sidebar.
55-
pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
5653
/// Shared mutable state.
5754
///
5855
/// Issue for improving the situation: [#82381][]
@@ -73,7 +70,7 @@ crate struct Context<'tcx> {
7370

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

7875
/// Shared mutable state used in [`Context`] and elsewhere.
7976
crate struct SharedContext<'tcx> {
@@ -474,7 +471,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
474471
dst,
475472
render_redirect_pages: false,
476473
id_map: RefCell::new(id_map),
477-
deref_id_map: RefCell::new(FxHashMap::default()),
478474
shared: Rc::new(scx),
479475
cache: Rc::new(cache),
480476
};
@@ -492,7 +488,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
492488
dst: self.dst.clone(),
493489
render_redirect_pages: self.render_redirect_pages,
494490
id_map: RefCell::new(IdMap::new()),
495-
deref_id_map: RefCell::new(FxHashMap::default()),
496491
shared: Rc::clone(&self.shared),
497492
cache: Rc::clone(&self.cache),
498493
}

src/librustdoc/html/render/mod.rs

+6-20
Original file line numberDiff line numberDiff line change
@@ -1017,17 +1017,12 @@ fn render_assoc_items(
10171017
RenderMode::Normal
10181018
}
10191019
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1020-
let id =
1021-
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1022-
debug!("Adding {} to deref id map", type_.print(cx));
1023-
cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
10241020
write!(
10251021
w,
1026-
"<h2 id=\"{id}\" class=\"small-section-header\">\
1022+
"<h2 id=\"deref-methods\" class=\"small-section-header\">\
10271023
Methods from {trait_}&lt;Target = {type_}&gt;\
1028-
<a href=\"#{id}\" class=\"anchor\"></a>\
1024+
<a href=\"#deref-methods\" class=\"anchor\"></a>\
10291025
</h2>",
1030-
id = id,
10311026
trait_ = trait_.print(cx),
10321027
type_ = type_.print(cx),
10331028
);
@@ -1052,6 +1047,9 @@ fn render_assoc_items(
10521047
);
10531048
}
10541049
}
1050+
if let AssocItemRender::DerefFor { .. } = what {
1051+
return;
1052+
}
10551053
if !traits.is_empty() {
10561054
let deref_impl = traits
10571055
.iter()
@@ -1062,13 +1060,6 @@ fn render_assoc_items(
10621060
.any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
10631061
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
10641062
}
1065-
1066-
// If we were already one level into rendering deref methods, we don't want to render
1067-
// anything after recursing into any further deref methods above.
1068-
if let AssocItemRender::DerefFor { .. } = what {
1069-
return;
1070-
}
1071-
10721063
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
10731064
traits.iter().partition(|t| t.inner_impl().synthetic);
10741065
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
@@ -1960,14 +1951,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
19601951
.flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
19611952
.collect::<Vec<_>>();
19621953
if !ret.is_empty() {
1963-
let deref_id_map = cx.deref_id_map.borrow();
1964-
let id = deref_id_map
1965-
.get(&real_target.def_id_full(c).unwrap())
1966-
.expect("Deref section without derived id");
19671954
write!(
19681955
out,
1969-
"<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
1970-
id,
1956+
"<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}&lt;Target={}&gt;</a>",
19711957
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
19721958
Escape(&format!("{:#}", real_target.print(cx))),
19731959
);

src/librustdoc/passes/collect_trait_impls.rs

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

6-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
6+
use rustc_data_structures::fx::FxHashSet;
77
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
88
use rustc_middle::ty::DefIdTree;
99
use rustc_span::symbol::sym;
@@ -53,6 +53,39 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
5353
}
5454
}
5555

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

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);
121-
add_deref_target(map, cleaner, &target_did);
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(type_did) {
130-
add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
131-
}
132-
}
133-
134120
let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
135121
items
136122
} else {
137123
panic!("collect-trait-impls can't run");
138124
};
139125

140126
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-
127+
items.extend(new_items);
154128
krate
155129
}
156130

@@ -204,13 +178,9 @@ impl BadImplStripper {
204178
} else if let Some(prim) = ty.primitive_type() {
205179
self.prims.contains(&prim)
206180
} else if let Some(did) = ty.def_id() {
207-
self.keep_impl_with_def_id(&did)
181+
self.items.contains(&did)
208182
} else {
209183
false
210184
}
211185
}
212-
213-
fn keep_impl_with_def_id(&self, did: &DefId) -> bool {
214-
self.items.contains(did)
215-
}
216186
}

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)