]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/clean/blanket_impl.rs
Merge branch 'master' into rusty-hermit
[rust.git] / src / librustdoc / clean / blanket_impl.rs
1 use rustc::hir;
2 use rustc::traits;
3 use rustc::ty::ToPredicate;
4 use rustc::ty::subst::Subst;
5 use rustc::infer::InferOk;
6 use rustc::hir::def_id::LOCAL_CRATE;
7 use syntax_pos::DUMMY_SP;
8
9 use super::*;
10
11 pub struct BlanketImplFinder<'a, 'tcx> {
12     pub cx: &'a core::DocContext<'tcx>,
13 }
14
15 impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
16     pub fn new(cx: &'a core::DocContext<'tcx>) -> Self {
17         BlanketImplFinder { cx }
18     }
19
20     // FIXME(eddyb) figure out a better way to pass information about
21     // parametrization of `ty` than `param_env_def_id`.
22     pub fn get_blanket_impls(
23         &self,
24         ty: Ty<'tcx>,
25         param_env_def_id: DefId,
26     ) -> Vec<Item> {
27         let param_env = self.cx.tcx.param_env(param_env_def_id);
28
29         debug!("get_blanket_impls({:?})", ty);
30         let mut impls = Vec::new();
31         for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() {
32             if !self.cx.renderinfo.borrow().access_levels.is_public(trait_def_id) ||
33                self.cx.generated_synthetics
34                       .borrow_mut()
35                       .get(&(ty, trait_def_id))
36                       .is_some() {
37                 continue
38             }
39             self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
40                 debug!("get_blanket_impls: Considering impl for trait '{:?}' {:?}",
41                         trait_def_id, impl_def_id);
42                 let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
43                 let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| {
44                     match trait_ref.self_ty().kind {
45                         ty::Param(_) => {},
46                         _ => return false,
47                     }
48
49                     let substs = infcx.fresh_substs_for_item(DUMMY_SP, param_env_def_id);
50                     let ty = ty.subst(infcx.tcx, substs);
51                     let param_env = param_env.subst(infcx.tcx, substs);
52
53                     let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
54                     let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
55
56                     // Require the type the impl is implemented on to match
57                     // our type, and ignore the impl if there was a mismatch.
58                     let cause = traits::ObligationCause::dummy();
59                     let eq_result = infcx.at(&cause, param_env)
60                                          .eq(trait_ref.self_ty(), ty);
61                     if let Ok(InferOk { value: (), obligations }) = eq_result {
62                         // FIXME(eddyb) ignoring `obligations` might cause false positives.
63                         drop(obligations);
64
65                         debug!(
66                             "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
67                              param_env, trait_ref, ty
68                         );
69                         match infcx.evaluate_obligation(
70                             &traits::Obligation::new(
71                                 cause,
72                                 param_env,
73                                 trait_ref.to_predicate(),
74                             ),
75                         ) {
76                             Ok(eval_result) => eval_result.may_apply(),
77                             Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no
78                         }
79                     } else {
80                         false
81                     }
82                 });
83                 debug!("get_blanket_impls: found applicable impl: {}\
84                         for trait_ref={:?}, ty={:?}",
85                         may_apply, trait_ref, ty);
86                 if !may_apply {
87                     return;
88                 }
89
90                 self.cx.generated_synthetics.borrow_mut()
91                                             .insert((ty, trait_def_id));
92                 let provided_trait_methods =
93                     self.cx.tcx.provided_trait_methods(trait_def_id)
94                                 .into_iter()
95                                 .map(|meth| meth.ident.to_string())
96                                 .collect();
97
98                 impls.push(Item {
99                     source: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
100                     name: None,
101                     attrs: Default::default(),
102                     visibility: Inherited,
103                     def_id: self.cx.next_def_id(impl_def_id.krate),
104                     stability: None,
105                     deprecation: None,
106                     inner: ImplItem(Impl {
107                         unsafety: hir::Unsafety::Normal,
108                         generics: (
109                             self.cx.tcx.generics_of(impl_def_id),
110                             self.cx.tcx.explicit_predicates_of(impl_def_id),
111                         ).clean(self.cx),
112                         provided_trait_methods,
113                         // FIXME(eddyb) compute both `trait_` and `for_` from
114                         // the post-inference `trait_ref`, as it's more accurate.
115                         trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
116                         for_: ty.clean(self.cx),
117                         items: self.cx.tcx.associated_items(impl_def_id)
118                                         .collect::<Vec<_>>()
119                                         .clean(self.cx),
120                         polarity: None,
121                         synthetic: false,
122                         blanket_impl: Some(trait_ref.self_ty().clean(self.cx)),
123                     }),
124                 });
125             });
126         }
127         impls
128     }
129 }