Skip to content

Commit dab7151

Browse files
committed
Auto merge of #52585 - GuillaumeGomez:generic-impls, r=QuietMisdreavus
[rustdoc] Generic impls Fixes #33772. r? @QuietMisdreavus
2 parents 4234adf + 06364bd commit dab7151

File tree

9 files changed

+246
-69
lines changed

9 files changed

+246
-69
lines changed

src/librustdoc/clean/auto_trait.rs

+145-26
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc::traits::auto_trait as auto;
12-
use rustc::ty::TypeFoldable;
1311
use rustc::hir;
12+
use rustc::traits::{self, auto_trait as auto};
13+
use rustc::ty::{self, ToPredicate, TypeFoldable};
14+
use rustc::ty::subst::Subst;
15+
use rustc::infer::InferOk;
1416
use std::fmt::Debug;
17+
use syntax_pos::DUMMY_SP;
18+
19+
use core::DocAccessLevels;
1520

1621
use super::*;
1722

@@ -75,6 +80,141 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
7580
self.get_auto_trait_impls(did, &def_ctor, Some(name))
7681
}
7782

83+
fn get_real_ty<F>(&self,
84+
def_id: DefId,
85+
def_ctor: &F,
86+
real_name: &Option<Ident>,
87+
generics: &ty::Generics,
88+
) -> hir::Ty
89+
where F: Fn(DefId) -> Def {
90+
let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
91+
let mut segments = path.segments.into_vec();
92+
let last = segments.pop().unwrap();
93+
94+
segments.push(hir::PathSegment::new(
95+
real_name.unwrap_or(last.ident),
96+
self.generics_to_path_params(generics.clone()),
97+
false,
98+
));
99+
100+
let new_path = hir::Path {
101+
span: path.span,
102+
def: path.def,
103+
segments: HirVec::from_vec(segments),
104+
};
105+
106+
hir::Ty {
107+
id: ast::DUMMY_NODE_ID,
108+
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
109+
span: DUMMY_SP,
110+
hir_id: hir::DUMMY_HIR_ID,
111+
}
112+
}
113+
114+
pub fn get_blanket_impls<F>(
115+
&self,
116+
def_id: DefId,
117+
def_ctor: &F,
118+
name: Option<String>,
119+
generics: &ty::Generics,
120+
) -> Vec<Item>
121+
where F: Fn(DefId) -> Def {
122+
let ty = self.cx.tcx.type_of(def_id);
123+
let mut traits = Vec::new();
124+
if self.cx.access_levels.borrow().is_doc_reachable(def_id) {
125+
let real_name = name.clone().map(|name| Ident::from_str(&name));
126+
let param_env = self.cx.tcx.param_env(def_id);
127+
for &trait_def_id in self.cx.all_traits.iter() {
128+
if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
129+
self.cx.generated_synthetics
130+
.borrow_mut()
131+
.get(&(def_id, trait_def_id))
132+
.is_some() {
133+
continue
134+
}
135+
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
136+
self.cx.tcx.infer_ctxt().enter(|infcx| {
137+
let t_generics = infcx.tcx.generics_of(impl_def_id);
138+
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap();
139+
140+
match infcx.tcx.type_of(impl_def_id).sty {
141+
::rustc::ty::TypeVariants::TyParam(_) => {},
142+
_ => return,
143+
}
144+
145+
let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
146+
let ty = ty.subst(infcx.tcx, substs);
147+
let param_env = param_env.subst(infcx.tcx, substs);
148+
149+
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
150+
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
151+
152+
// Require the type the impl is implemented on to match
153+
// our type, and ignore the impl if there was a mismatch.
154+
let cause = traits::ObligationCause::dummy();
155+
let eq_result = infcx.at(&cause, param_env)
156+
.eq(trait_ref.self_ty(), ty);
157+
if let Ok(InferOk { value: (), obligations }) = eq_result {
158+
// FIXME(eddyb) ignoring `obligations` might cause false positives.
159+
drop(obligations);
160+
161+
let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
162+
cause.clone(),
163+
param_env,
164+
trait_ref.to_predicate(),
165+
));
166+
if !may_apply {
167+
return
168+
}
169+
self.cx.generated_synthetics.borrow_mut()
170+
.insert((def_id, trait_def_id));
171+
let trait_ = hir::TraitRef {
172+
path: get_path_for_type(infcx.tcx,
173+
trait_def_id,
174+
hir::def::Def::Trait),
175+
ref_id: ast::DUMMY_NODE_ID,
176+
};
177+
let provided_trait_methods =
178+
infcx.tcx.provided_trait_methods(trait_def_id)
179+
.into_iter()
180+
.map(|meth| meth.ident.to_string())
181+
.collect();
182+
183+
let ty = self.get_real_ty(def_id, def_ctor, &real_name, generics);
184+
let predicates = infcx.tcx.predicates_of(impl_def_id);
185+
186+
traits.push(Item {
187+
source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
188+
name: None,
189+
attrs: Default::default(),
190+
visibility: None,
191+
def_id: self.next_def_id(impl_def_id.krate),
192+
stability: None,
193+
deprecation: None,
194+
inner: ImplItem(Impl {
195+
unsafety: hir::Unsafety::Normal,
196+
generics: (t_generics, &predicates).clean(self.cx),
197+
provided_trait_methods,
198+
trait_: Some(trait_.clean(self.cx)),
199+
for_: ty.clean(self.cx),
200+
items: infcx.tcx.associated_items(impl_def_id)
201+
.collect::<Vec<_>>()
202+
.clean(self.cx),
203+
polarity: None,
204+
synthetic: false,
205+
blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
206+
.clean(self.cx)),
207+
}),
208+
});
209+
debug!("{:?} => {}", trait_ref, may_apply);
210+
}
211+
});
212+
});
213+
}
214+
}
215+
traits
216+
}
217+
78218
pub fn get_auto_trait_impls<F>(
79219
&self,
80220
def_id: DefId,
@@ -122,6 +262,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
122262
def_ctor,
123263
tcx.require_lang_item(lang_items::SyncTraitLangItem),
124264
).into_iter())
265+
.chain(self.get_blanket_impls(def_id, def_ctor, name, &generics).into_iter())
125266
.collect();
126267

127268
debug!(
@@ -196,31 +337,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
196337
}
197338
_ => unreachable!(),
198339
};
199-
200-
let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
201-
let mut segments = path.segments.into_vec();
202-
let last = segments.pop().unwrap();
203-
204340
let real_name = name.map(|name| Ident::from_str(&name));
205-
206-
segments.push(hir::PathSegment::new(
207-
real_name.unwrap_or(last.ident),
208-
self.generics_to_path_params(generics.clone()),
209-
false,
210-
));
211-
212-
let new_path = hir::Path {
213-
span: path.span,
214-
def: path.def,
215-
segments: HirVec::from_vec(segments),
216-
};
217-
218-
let ty = hir::Ty {
219-
id: ast::DUMMY_NODE_ID,
220-
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
221-
span: DUMMY_SP,
222-
hir_id: hir::DUMMY_HIR_ID,
223-
};
341+
let ty = self.get_real_ty(def_id, def_ctor, &real_name, &generics);
224342

225343
return Some(Item {
226344
source: Span::empty(),
@@ -239,6 +357,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
239357
items: Vec::new(),
240358
polarity,
241359
synthetic: true,
360+
blanket_impl: None,
242361
}),
243362
});
244363
}

src/librustdoc/clean/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
275275
if auto_traits {
276276
let auto_impls = get_auto_traits_with_def_id(cx, did);
277277
let mut renderinfo = cx.renderinfo.borrow_mut();
278-
279278
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
280279
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
281280

@@ -415,6 +414,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
415414
items: trait_items,
416415
polarity: Some(polarity.clean(cx)),
417416
synthetic: false,
417+
blanket_impl: None,
418418
}),
419419
source: tcx.def_span(did).clean(cx),
420420
name: None,

src/librustdoc/clean/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,6 @@ impl GenericBound {
15491549
}
15501550

15511551
fn get_trait_type(&self) -> Option<Type> {
1552-
15531552
if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
15541553
return Some(trait_.clone());
15551554
}
@@ -3880,6 +3879,7 @@ pub struct Impl {
38803879
pub items: Vec<Item>,
38813880
pub polarity: Option<ImplPolarity>,
38823881
pub synthetic: bool,
3882+
pub blanket_impl: Option<Type>,
38833883
}
38843884

38853885
pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
@@ -3947,6 +3947,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
39473947
items,
39483948
polarity: Some(self.polarity.clean(cx)),
39493949
synthetic: false,
3950+
blanket_impl: None,
39503951
})
39513952
});
39523953
ret

src/librustdoc/core.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use rustc_lint;
1212
use rustc_driver::{self, driver, target_features, abort_on_err};
1313
use rustc::session::{self, config};
14-
use rustc::hir::def_id::{DefId, CrateNum};
14+
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
1515
use rustc::hir::def::Def;
1616
use rustc::middle::cstore::CrateStore;
1717
use rustc::middle::privacy::AccessLevels;
@@ -84,6 +84,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
8484
/// Maps (type_id, trait_id) -> auto trait impl
8585
pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
8686
pub current_item_name: RefCell<Option<Name>>,
87+
pub all_traits: Vec<DefId>,
8788
}
8889

8990
impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
@@ -386,6 +387,7 @@ pub fn run_core(search_paths: SearchPaths,
386387
all_fake_def_ids: RefCell::new(FxHashSet()),
387388
generated_synthetics: RefCell::new(FxHashSet()),
388389
current_item_name: RefCell::new(None),
390+
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
389391
};
390392
debug!("crate: {:?}", tcx.hir.krate());
391393

src/librustdoc/html/format.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,11 @@ fn fmt_impl(i: &clean::Impl,
769769
write!(f, " for ")?;
770770
}
771771

772-
fmt_type(&i.for_, f, use_absolute)?;
772+
if let Some(ref ty) = i.blanket_impl {
773+
fmt_type(ty, f, use_absolute)?;
774+
} else {
775+
fmt_type(&i.for_, f, use_absolute)?;
776+
}
773777

774778
fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
775779
Ok(())

0 commit comments

Comments
 (0)