From a6fa92cbfd477655e6aa6abcf1a9a77dbec35648 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Jan 2021 22:03:20 +0000 Subject: [PATCH] Balance sidebar `Deref` cycle check with main content The `Deref` cycle checks added as part of #80653 were "unbalanced" in the sense that the main content code path checks for cycles _before_ descending, while the sidebar checks _after_. Checking _before_ is correct, so this changes the sidebar path to match the main content path. --- src/librustdoc/html/render/mod.rs | 18 +++++++++++------- src/test/rustdoc-ui/deref-generic.rs | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 src/test/rustdoc-ui/deref-generic.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index bb9a7be590e87..2939535bd54e6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -3518,6 +3518,7 @@ fn render_assoc_items( "deref-methods-{:#}", type_.print(cx.cache()) ))); + debug!("Adding {} to deref id map", type_.print(cx.cache())); cx.deref_id_map .borrow_mut() .insert(type_.def_id_full(cx.cache()).unwrap(), id.clone()); @@ -3636,6 +3637,7 @@ fn render_deref_methods( _ => None, }) .expect("Expected associated type binding"); + debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target); let what = AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut }; if let Some(did) = target.def_id_full(cx.cache()) { @@ -4396,6 +4398,15 @@ fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec) -> Strin }) { debug!("found target, real_target: {:?} {:?}", target, real_target); + if let Some(did) = target.def_id_full(cx.cache()) { + if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) { + // `impl Deref for S` + if did == type_did { + // Avoid infinite cycles + return out; + } + } + } let deref_mut = v .iter() .filter(|i| i.inner_impl().trait_.is_some()) @@ -4439,13 +4450,6 @@ fn sidebar_deref_methods(cx: &Context<'_>, impl_: &Impl, v: &Vec) -> Strin .filter(|i| i.inner_impl().trait_.is_some()) .find(|i| i.inner_impl().trait_.def_id_full(cx.cache()) == c.deref_trait_did) { - if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) { - // `impl Deref for S` - if target_did == type_did { - // Avoid infinite cycles - return out; - } - } out.push_str(&sidebar_deref_methods(cx, target_deref_impl, target_impls)); } } diff --git a/src/test/rustdoc-ui/deref-generic.rs b/src/test/rustdoc-ui/deref-generic.rs new file mode 100644 index 0000000000000..bc64beb1b939d --- /dev/null +++ b/src/test/rustdoc-ui/deref-generic.rs @@ -0,0 +1,15 @@ +// check-pass +// #81395: Fix ICE when recursing into Deref target only differing in type args + +pub struct Generic(T); + +impl<'a> std::ops::Deref for Generic<&'a mut ()> { + type Target = Generic<&'a ()>; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +impl<'a> Generic<&'a ()> { + pub fn some_method(&self) {} +}