Skip to content

Commit

Permalink
Rollup merge of #68093 - GuillaumeGomez:fix-deref-impl-typedef, r=oli…
Browse files Browse the repository at this point in the history
…-obk

Fix deref impl typedef

Fixes #35295.

r? @kinnison
  • Loading branch information
tmandry authored Jan 18, 2020
2 parents c854aec + 482dc77 commit bafe089
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 25 deletions.
16 changes: 16 additions & 0 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,22 @@ fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
clean::Typedef {
type_: cx.tcx.type_of(did).clean(cx),
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
item_type: build_type_alias_type(cx, did),
}
}

fn build_type_alias_type(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
let type_ = cx.tcx.type_of(did).clean(cx);
type_.def_id().and_then(|did| build_ty(cx, did))
}

pub fn build_ty(cx: &DocContext, did: DefId) -> Option<clean::Type> {
match cx.tcx.def_kind(did)? {
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Const | DefKind::Static => {
Some(cx.tcx.type_of(did).clean(cx))
}
DefKind::TyAlias => build_type_alias_type(cx, did),
_ => None,
}
}

Expand Down
35 changes: 24 additions & 11 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,9 @@ impl Clean<Item> for hir::ImplItem<'_> {
MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx))
}
hir::ImplItemKind::TyAlias(ref ty) => {
TypedefItem(Typedef { type_: ty.clean(cx), generics: Generics::default() }, true)
let type_ = ty.clean(cx);
let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true)
}
hir::ImplItemKind::OpaqueTy(ref bounds) => OpaqueTyItem(
OpaqueTy { bounds: bounds.clean(cx), generics: Generics::default() },
Expand Down Expand Up @@ -1282,10 +1284,13 @@ impl Clean<Item> for ty::AssocItem {

AssocTypeItem(bounds, ty.clean(cx))
} else {
let type_ = cx.tcx.type_of(self.def_id).clean(cx);
let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
TypedefItem(
Typedef {
type_: cx.tcx.type_of(self.def_id).clean(cx),
type_,
generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
item_type,
},
true,
)
Expand Down Expand Up @@ -1989,6 +1994,8 @@ impl Clean<String> for ast::Name {

impl Clean<Item> for doctree::Typedef<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let type_ = self.ty.clean(cx);
let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
Expand All @@ -1997,10 +2004,7 @@ impl Clean<Item> for doctree::Typedef<'_> {
visibility: self.vis.clean(cx),
stability: cx.stability(self.id).clean(cx),
deprecation: cx.deprecation(self.id).clean(cx),
inner: TypedefItem(
Typedef { type_: self.ty.clean(cx), generics: self.gen.clean(cx) },
false,
),
inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
}
}
}
Expand Down Expand Up @@ -2101,7 +2105,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
build_deref_target_impls(cx, &items, &mut ret);
}

let provided = trait_
let provided: FxHashSet<String> = trait_
.def_id()
.map(|did| {
cx.tcx
Expand All @@ -2112,7 +2116,12 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
})
.unwrap_or_default();

ret.push(Item {
let for_ = self.for_.clean(cx);
let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
Some(DefKind::TyAlias) => Some(cx.tcx.type_of(did).clean(cx)),
_ => None,
});
let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| Item {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
Expand All @@ -2123,15 +2132,19 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
inner: ImplItem(Impl {
unsafety: self.unsafety,
generics: self.generics.clean(cx),
provided_trait_methods: provided,
provided_trait_methods: provided.clone(),
trait_,
for_: self.for_.clean(cx),
for_,
items,
polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
synthetic: false,
blanket_impl: None,
}),
});
};
if let Some(type_alias) = type_alias {
ret.push(make_item(trait_.clone(), type_alias, items.clone()));
}
ret.push(make_item(trait_, for_, items));
ret
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,14 @@ pub struct PathSegment {
pub struct Typedef {
pub type_: Type,
pub generics: Generics,
// Type of target item.
pub item_type: Option<Type>,
}

impl GetDefId for Typedef {
fn def_id(&self) -> Option<DefId> {
self.type_.def_id()
}
}

#[derive(Clone, Debug)]
Expand Down
20 changes: 13 additions & 7 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3469,20 +3469,23 @@ fn render_deref_methods(
deref_mut: bool,
) {
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
let target = impl_
let (target, real_target) = impl_
.inner_impl()
.items
.iter()
.filter_map(|item| match item.inner {
clean::TypedefItem(ref t, true) => Some(&t.type_),
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
}),
_ => None,
})
.next()
.expect("Expected associated type binding");
let what =
AssocItemRender::DerefFor { trait_: deref_type, type_: target, deref_mut_: deref_mut };
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
if let Some(did) = target.def_id() {
render_assoc_items(w, cx, container_item, did, what)
render_assoc_items(w, cx, container_item, did, what);
} else {
if let Some(prim) = target.primitive_type() {
if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
Expand Down Expand Up @@ -4123,12 +4126,15 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
.filter(|i| i.inner_impl().trait_.is_some())
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
{
if let Some(target) = impl_
if let Some((target, real_target)) = impl_
.inner_impl()
.items
.iter()
.filter_map(|item| match item.inner {
clean::TypedefItem(ref t, true) => Some(&t.type_),
clean::TypedefItem(ref t, true) => Some(match *t {
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
_ => (&t.type_, &t.type_),
}),
_ => None,
})
.next()
Expand All @@ -4147,7 +4153,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
"{:#}",
impl_.inner_impl().trait_.as_ref().unwrap().print()
)),
Escape(&format!("{:#}", target.print()))
Escape(&format!("{:#}", real_target.print()))
));
out.push_str("</a>");
let mut ret = impls
Expand Down
14 changes: 7 additions & 7 deletions src/librustdoc/html/render/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ impl DocFolder for Cache {
| clean::StructFieldItem(..)
| clean::VariantItem(..) => (
(
Some(*self.parent_stack.last().unwrap()),
Some(*self.parent_stack.last().expect("parent_stack is empty")),
Some(&self.stack[..self.stack.len() - 1]),
),
false,
Expand All @@ -286,7 +286,7 @@ impl DocFolder for Cache {
if self.parent_stack.is_empty() {
((None, None), false)
} else {
let last = self.parent_stack.last().unwrap();
let last = self.parent_stack.last().expect("parent_stack is empty 2");
let did = *last;
let path = match self.paths.get(&did) {
// The current stack not necessarily has correlation
Expand Down Expand Up @@ -468,7 +468,7 @@ impl DocFolder for Cache {
self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
}
} else {
let trait_did = impl_item.trait_did().unwrap();
let trait_did = impl_item.trait_did().expect("no trait did");
self.orphan_trait_impls.push((trait_did, dids, impl_item));
}
None
Expand All @@ -478,10 +478,10 @@ impl DocFolder for Cache {
});

if pushed {
self.stack.pop().unwrap();
self.stack.pop().expect("stack already empty");
}
if parent_pushed {
self.parent_stack.pop().unwrap();
self.parent_stack.pop().expect("parent stack already empty");
}
self.stripped_mod = orig_stripped_mod;
self.parent_is_trait_impl = orig_parent_is_trait_impl;
Expand Down Expand Up @@ -594,7 +594,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
for item in search_index {
item.parent_idx = item.parent.map(|nodeid| {
if nodeid_to_pathid.contains_key(&nodeid) {
*nodeid_to_pathid.get(&nodeid).unwrap()
*nodeid_to_pathid.get(&nodeid).expect("no pathid")
} else {
let pathid = lastpathid;
nodeid_to_pathid.insert(nodeid, pathid);
Expand Down Expand Up @@ -639,7 +639,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
items: crate_items,
paths: crate_paths,
})
.unwrap()
.expect("failed serde conversion")
)
}

Expand Down
33 changes: 33 additions & 0 deletions src/test/rustdoc/deref-typedef.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#![crate_name = "foo"]

// @has 'foo/struct.Bar.html'
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooC>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
// @has '-' '//*[@class="sidebar-title"]' 'Methods from Deref<Target=FooC>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'

pub struct FooA;
pub type FooB = FooA;
pub type FooC = FooB;

impl FooA {
pub fn foo_a(&self) {}
}

impl FooB {
pub fn foo_b(&self) {}
}

impl FooC {
pub fn foo_c(&self) {}
}

pub struct Bar;
impl std::ops::Deref for Bar {
type Target = FooC;
fn deref(&self) -> &Self::Target { unimplemented!() }
}

0 comments on commit bafe089

Please sign in to comment.