]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/trait_def.rs
Use 128 instead of 64 bits for DefPath hashes
[rust.git] / src / librustc / ty / trait_def.rs
1 // Copyright 2012-2015 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 hir::def_id::DefId;
12 use ich::Fingerprint;
13 use traits::specialization_graph;
14 use ty::fast_reject;
15 use ty::fold::TypeFoldable;
16 use ty::{Ty, TyCtxt};
17 use std::rc::Rc;
18 use hir;
19
20 /// A trait's definition with type information.
21 pub struct TraitDef {
22     pub def_id: DefId,
23
24     pub unsafety: hir::Unsafety,
25
26     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
27     /// attribute, indicating that it should be used with `Foo()`
28     /// sugar. This is a temporary thing -- eventually any trait will
29     /// be usable with the sugar (or without it).
30     pub paren_sugar: bool,
31
32     pub has_default_impl: bool,
33
34     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
35     /// recomputed all the time.
36     pub def_path_hash: Fingerprint,
37 }
38
39 // We don't store the list of impls in a flat list because each cached list of
40 // `relevant_impls_for` we would then duplicate all blanket impls. By keeping
41 // blanket and non-blanket impls separate, we can share the list of blanket
42 // impls.
43 #[derive(Clone)]
44 pub struct TraitImpls {
45     blanket_impls: Rc<Vec<DefId>>,
46     non_blanket_impls: Rc<Vec<DefId>>,
47 }
48
49 impl TraitImpls {
50     pub fn iter(&self) -> TraitImplsIter {
51         TraitImplsIter {
52             blanket_impls: self.blanket_impls.clone(),
53             non_blanket_impls: self.non_blanket_impls.clone(),
54             index: 0
55         }
56     }
57 }
58
59 #[derive(Clone)]
60 pub struct TraitImplsIter {
61     blanket_impls: Rc<Vec<DefId>>,
62     non_blanket_impls: Rc<Vec<DefId>>,
63     index: usize,
64 }
65
66 impl Iterator for TraitImplsIter {
67     type Item = DefId;
68
69     fn next(&mut self) -> Option<DefId> {
70         if self.index < self.blanket_impls.len() {
71             let bi_index = self.index;
72             self.index += 1;
73             Some(self.blanket_impls[bi_index])
74         } else {
75             let nbi_index = self.index - self.blanket_impls.len();
76             if nbi_index < self.non_blanket_impls.len() {
77                 self.index += 1;
78                 Some(self.non_blanket_impls[nbi_index])
79             } else {
80                 None
81             }
82         }
83     }
84
85     fn size_hint(&self) -> (usize, Option<usize>) {
86         let items_left = (self.blanket_impls.len() + self.non_blanket_impls.len()) - self.index;
87         (items_left, Some(items_left))
88     }
89 }
90
91 impl ExactSizeIterator for TraitImplsIter {}
92
93 impl<'a, 'gcx, 'tcx> TraitDef {
94     pub fn new(def_id: DefId,
95                unsafety: hir::Unsafety,
96                paren_sugar: bool,
97                has_default_impl: bool,
98                def_path_hash: Fingerprint)
99                -> TraitDef {
100         TraitDef {
101             def_id,
102             paren_sugar,
103             unsafety,
104             has_default_impl,
105             def_path_hash,
106         }
107     }
108
109     pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
110                      of_impl: DefId)
111                      -> specialization_graph::Ancestors {
112         specialization_graph::ancestors(tcx, self.def_id, of_impl)
113     }
114
115     pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
116         for impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
117             f(impl_def_id);
118         }
119     }
120
121     /// Iterate over every impl that could possibly match the
122     /// self-type `self_ty`.
123     pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
124                                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
125                                                    self_ty: Ty<'tcx>,
126                                                    mut f: F)
127     {
128         // simplify_type(.., false) basically replaces type parameters and
129         // projections with infer-variables. This is, of course, done on
130         // the impl trait-ref when it is instantiated, but not on the
131         // predicate trait-ref which is passed here.
132         //
133         // for example, if we match `S: Copy` against an impl like
134         // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
135         // in `Option<T>` with an infer variable, to `Option<_>` (this
136         // doesn't actually change fast_reject output), but we don't
137         // replace `S` with anything - this impl of course can't be
138         // selected, and as there are hundreds of similar impls,
139         // considering them would significantly harm performance.
140         let relevant_impls = if let Some(simplified_self_ty) =
141                 fast_reject::simplify_type(tcx, self_ty, true) {
142             tcx.relevant_trait_impls_for((self.def_id, simplified_self_ty))
143         } else {
144             tcx.trait_impls_of(self.def_id)
145         };
146
147         for impl_def_id in relevant_impls.iter() {
148             f(impl_def_id);
149         }
150     }
151 }
152
153 // Query provider for `trait_impls_of`.
154 pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
155                                                 trait_id: DefId)
156                                                 -> TraitImpls {
157     let remote_impls = if trait_id.is_local() {
158         // Traits defined in the current crate can't have impls in upstream
159         // crates, so we don't bother querying the cstore.
160         Vec::new()
161     } else {
162         tcx.sess.cstore.implementations_of_trait(Some(trait_id))
163     };
164
165     let mut blanket_impls = Vec::new();
166     let mut non_blanket_impls = Vec::new();
167
168     let local_impls = tcx.hir
169                          .trait_impls(trait_id)
170                          .into_iter()
171                          .map(|&node_id| tcx.hir.local_def_id(node_id));
172
173      for impl_def_id in local_impls.chain(remote_impls.into_iter()) {
174         let impl_self_ty = tcx.type_of(impl_def_id);
175         if impl_def_id.is_local() && impl_self_ty.references_error() {
176             continue
177         }
178
179         if fast_reject::simplify_type(tcx, impl_self_ty, false).is_some() {
180             non_blanket_impls.push(impl_def_id);
181         } else {
182             blanket_impls.push(impl_def_id);
183         }
184     }
185
186     TraitImpls {
187         blanket_impls: Rc::new(blanket_impls),
188         non_blanket_impls: Rc::new(non_blanket_impls),
189     }
190 }
191
192 // Query provider for `relevant_trait_impls_for`.
193 pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
194     tcx: TyCtxt<'a, 'tcx, 'tcx>,
195     (trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
196     -> TraitImpls
197 {
198     let all_trait_impls = tcx.trait_impls_of(trait_id);
199
200     let relevant: Vec<DefId> = all_trait_impls
201         .non_blanket_impls
202         .iter()
203         .cloned()
204         .filter(|&impl_def_id| {
205             let impl_self_ty = tcx.type_of(impl_def_id);
206             let impl_simple_self_ty = fast_reject::simplify_type(tcx,
207                                                                  impl_self_ty,
208                                                                  false).unwrap();
209             impl_simple_self_ty == self_ty
210         })
211         .collect();
212
213     if all_trait_impls.non_blanket_impls.len() == relevant.len() {
214         // If we didn't filter anything out, re-use the existing vec.
215         all_trait_impls
216     } else {
217         TraitImpls {
218             blanket_impls: all_trait_impls.blanket_impls.clone(),
219             non_blanket_impls: Rc::new(relevant),
220         }
221     }
222 }