Skip to content

Commit 667fdc1

Browse files
committed
Auto merge of #52827 - GuillaumeGomez:generic-impls, r=QuietMisdreavus
rustdoc: clean up generic impls r? @QuietMisdreavus
2 parents 94c3c34 + d57f3a6 commit 667fdc1

File tree

10 files changed

+481
-329
lines changed

10 files changed

+481
-329
lines changed

src/librustdoc/clean/auto_trait.rs

+23-299
Large diffs are not rendered by default.

src/librustdoc/clean/blanket_impl.rs

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::hir;
12+
use rustc::traits;
13+
use rustc::ty::ToPredicate;
14+
use rustc::ty::subst::Subst;
15+
use rustc::infer::InferOk;
16+
use syntax_pos::DUMMY_SP;
17+
18+
use core::DocAccessLevels;
19+
20+
use super::*;
21+
22+
use self::def_ctor::{get_def_from_def_id, get_def_from_node_id};
23+
24+
pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
25+
pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
26+
}
27+
28+
impl<'a, 'tcx, 'rcx, 'cstore> BlanketImplFinder <'a, 'tcx, 'rcx, 'cstore> {
29+
pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
30+
BlanketImplFinder { cx }
31+
}
32+
33+
pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
34+
get_def_from_def_id(&self.cx, def_id, &|def_ctor| {
35+
self.get_blanket_impls(def_id, &def_ctor, None)
36+
})
37+
}
38+
39+
pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
40+
get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| {
41+
let did = self.cx.tcx.hir.local_def_id(id);
42+
self.get_blanket_impls(did, &def_ctor, Some(name))
43+
})
44+
}
45+
46+
pub fn get_blanket_impls<F>(
47+
&self,
48+
def_id: DefId,
49+
def_ctor: &F,
50+
name: Option<String>,
51+
) -> Vec<Item>
52+
where F: Fn(DefId) -> Def {
53+
let mut impls = Vec::new();
54+
if self.cx
55+
.tcx
56+
.get_attrs(def_id)
57+
.lists("doc")
58+
.has_word("hidden")
59+
{
60+
debug!(
61+
"get_blanket_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \
62+
aborting",
63+
def_id
64+
);
65+
return impls;
66+
}
67+
let ty = self.cx.tcx.type_of(def_id);
68+
if self.cx.access_levels.borrow().is_doc_reachable(def_id) || ty.is_primitive() {
69+
let generics = self.cx.tcx.generics_of(def_id);
70+
let real_name = name.clone().map(|name| Ident::from_str(&name));
71+
let param_env = self.cx.tcx.param_env(def_id);
72+
for &trait_def_id in self.cx.all_traits.iter() {
73+
if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
74+
self.cx.generated_synthetics
75+
.borrow_mut()
76+
.get(&(def_id, trait_def_id))
77+
.is_some() {
78+
continue
79+
}
80+
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
81+
self.cx.tcx.infer_ctxt().enter(|infcx| {
82+
let t_generics = infcx.tcx.generics_of(impl_def_id);
83+
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id)
84+
.expect("Cannot get impl trait");
85+
86+
match trait_ref.self_ty().sty {
87+
ty::TypeVariants::TyParam(_) => {},
88+
_ => return,
89+
}
90+
91+
let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
92+
let ty = ty.subst(infcx.tcx, substs);
93+
let param_env = param_env.subst(infcx.tcx, substs);
94+
95+
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
96+
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
97+
98+
// Require the type the impl is implemented on to match
99+
// our type, and ignore the impl if there was a mismatch.
100+
let cause = traits::ObligationCause::dummy();
101+
let eq_result = infcx.at(&cause, param_env)
102+
.eq(trait_ref.self_ty(), ty);
103+
if let Ok(InferOk { value: (), obligations }) = eq_result {
104+
// FIXME(eddyb) ignoring `obligations` might cause false positives.
105+
drop(obligations);
106+
107+
let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
108+
cause.clone(),
109+
param_env,
110+
trait_ref.to_predicate(),
111+
));
112+
if !may_apply {
113+
return
114+
}
115+
self.cx.generated_synthetics.borrow_mut()
116+
.insert((def_id, trait_def_id));
117+
let trait_ = hir::TraitRef {
118+
path: get_path_for_type(infcx.tcx,
119+
trait_def_id,
120+
hir::def::Def::Trait),
121+
ref_id: ast::DUMMY_NODE_ID,
122+
};
123+
let provided_trait_methods =
124+
infcx.tcx.provided_trait_methods(trait_def_id)
125+
.into_iter()
126+
.map(|meth| meth.ident.to_string())
127+
.collect();
128+
129+
let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics);
130+
let predicates = infcx.tcx.predicates_of(impl_def_id);
131+
132+
impls.push(Item {
133+
source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
134+
name: None,
135+
attrs: Default::default(),
136+
visibility: None,
137+
def_id: self.cx.next_def_id(impl_def_id.krate),
138+
stability: None,
139+
deprecation: None,
140+
inner: ImplItem(Impl {
141+
unsafety: hir::Unsafety::Normal,
142+
generics: (t_generics, &predicates).clean(self.cx),
143+
provided_trait_methods,
144+
trait_: Some(trait_.clean(self.cx)),
145+
for_: ty.clean(self.cx),
146+
items: infcx.tcx.associated_items(impl_def_id)
147+
.collect::<Vec<_>>()
148+
.clean(self.cx),
149+
polarity: None,
150+
synthetic: false,
151+
blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
152+
.clean(self.cx)),
153+
}),
154+
});
155+
}
156+
});
157+
});
158+
}
159+
}
160+
impls
161+
}
162+
}

src/librustdoc/clean/def_ctor.rs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use core::DocContext;
12+
13+
use super::*;
14+
15+
pub fn get_def_from_def_id<F>(cx: &DocContext,
16+
def_id: DefId,
17+
callback: &F,
18+
) -> Vec<Item>
19+
where F: Fn(& dyn Fn(DefId) -> Def) -> Vec<Item> {
20+
let ty = cx.tcx.type_of(def_id);
21+
22+
match ty.sty {
23+
ty::TyAdt(adt, _) => callback(&match adt.adt_kind() {
24+
AdtKind::Struct => Def::Struct,
25+
AdtKind::Enum => Def::Enum,
26+
AdtKind::Union => Def::Union,
27+
}),
28+
ty::TyInt(_) |
29+
ty::TyUint(_) |
30+
ty::TyFloat(_) |
31+
ty::TyStr |
32+
ty::TyBool |
33+
ty::TyChar => callback(&move |_: DefId| {
34+
match ty.sty {
35+
ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
36+
ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
37+
ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
38+
ty::TyStr => Def::PrimTy(hir::TyStr),
39+
ty::TyBool => Def::PrimTy(hir::TyBool),
40+
ty::TyChar => Def::PrimTy(hir::TyChar),
41+
_ => unreachable!(),
42+
}
43+
}),
44+
_ => {
45+
debug!("Unexpected type {:?}", def_id);
46+
Vec::new()
47+
}
48+
}
49+
}
50+
51+
pub fn get_def_from_node_id<F>(cx: &DocContext,
52+
id: ast::NodeId,
53+
name: String,
54+
callback: &F,
55+
) -> Vec<Item>
56+
where F: Fn(& dyn Fn(DefId) -> Def, String) -> Vec<Item> {
57+
let item = &cx.tcx.hir.expect_item(id).node;
58+
59+
callback(&match *item {
60+
hir::ItemKind::Struct(_, _) => Def::Struct,
61+
hir::ItemKind::Union(_, _) => Def::Union,
62+
hir::ItemKind::Enum(_, _) => Def::Enum,
63+
_ => panic!("Unexpected type {:?} {:?}", item, id),
64+
}, name)
65+
}

src/librustdoc/clean/inline.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ use rustc::util::nodemap::FxHashSet;
2525

2626
use core::{DocContext, DocAccessLevels};
2727
use doctree;
28-
use clean::{self, GetDefId, ToSource, get_auto_traits_with_def_id};
28+
use clean::{
29+
self,
30+
GetDefId,
31+
ToSource,
32+
get_auto_traits_with_def_id,
33+
get_blanket_impls_with_def_id,
34+
};
2935

3036
use super::Clean;
3137

@@ -168,7 +174,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
168174
}
169175
});
170176
let fqn = if let clean::TypeKind::Macro = kind {
171-
vec![crate_name, relative.last().unwrap()]
177+
vec![crate_name, relative.last().expect("relative was empty")]
172178
} else {
173179
once(crate_name).chain(relative).collect()
174180
};
@@ -274,11 +280,14 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
274280

275281
if auto_traits {
276282
let auto_impls = get_auto_traits_with_def_id(cx, did);
277-
let mut renderinfo = cx.renderinfo.borrow_mut();
278-
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
279-
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
283+
{
284+
let mut renderinfo = cx.renderinfo.borrow_mut();
285+
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
286+
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
280287

281-
impls.extend(new_impls);
288+
impls.extend(new_impls);
289+
}
290+
impls.extend(get_blanket_impls_with_def_id(cx, did));
282291
}
283292

284293
// If this is the first time we've inlined something from another crate, then
@@ -336,10 +345,13 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
336345
build_impl(cx, def_id, &mut impls);
337346

338347
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
348+
let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
339349
let mut renderinfo = cx.renderinfo.borrow_mut();
340350

341351
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
342-
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
352+
.chain(blanket_impls.into_iter())
353+
.filter(|i| renderinfo.inlined.insert(i.def_id))
354+
.collect();
343355

344356
impls.extend(new_impls);
345357
}

0 commit comments

Comments
 (0)