]>
Commit | Line | Data |
---|---|---|
7453a54e SL |
1 | // Representing terms |
2 | // | |
3 | // Terms are structured as a straightforward tree. Rather than rely on | |
4 | // GC, we allocate terms out of a bounded arena (the lifetime of this | |
5 | // arena is the lifetime 'a that is threaded around). | |
6 | // | |
7 | // We assign a unique index to each type/region parameter whose variance | |
8 | // is to be inferred. We refer to such variables as "inferreds". An | |
9 | // `InferredIndex` is a newtype'd int representing the index of such | |
10 | // a variable. | |
11 | ||
29967ef6 | 12 | use rustc_arena::DroplessArena; |
dfeec247 XL |
13 | use rustc_hir as hir; |
14 | use rustc_hir::itemlikevisit::ItemLikeVisitor; | |
15 | use rustc_hir::HirIdMap; | |
ba9703b0 | 16 | use rustc_middle::ty::{self, TyCtxt}; |
7453a54e | 17 | use std::fmt; |
7453a54e SL |
18 | |
19 | use self::VarianceTerm::*; | |
7453a54e SL |
20 | |
21 | pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; | |
22 | ||
23 | #[derive(Copy, Clone, Debug)] | |
24 | pub struct InferredIndex(pub usize); | |
25 | ||
26 | #[derive(Copy, Clone)] | |
27 | pub enum VarianceTerm<'a> { | |
28 | ConstantTerm(ty::Variance), | |
29 | TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>), | |
30 | InferredTerm(InferredIndex), | |
31 | } | |
32 | ||
33 | impl<'a> fmt::Debug for VarianceTerm<'a> { | |
9fa01778 | 34 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
7453a54e SL |
35 | match *self { |
36 | ConstantTerm(c1) => write!(f, "{:?}", c1), | |
37 | TransformTerm(v1, v2) => write!(f, "({:?} \u{00D7} {:?})", v1, v2), | |
dfeec247 XL |
38 | InferredTerm(id) => write!(f, "[{}]", { |
39 | let InferredIndex(i) = id; | |
40 | i | |
41 | }), | |
7453a54e SL |
42 | } |
43 | } | |
44 | } | |
45 | ||
46 | // The first pass over the crate simply builds up the set of inferreds. | |
47 | ||
dc9dc135 XL |
48 | pub struct TermsContext<'a, 'tcx> { |
49 | pub tcx: TyCtxt<'tcx>, | |
29967ef6 | 50 | pub arena: &'a DroplessArena, |
7453a54e | 51 | |
7453a54e SL |
52 | // For marker types, UnsafeCell, and other lang items where |
53 | // variance is hardcoded, records the item-id and the hardcoded | |
54 | // variance. | |
532ac7d7 | 55 | pub lang_items: Vec<(hir::HirId, Vec<ty::Variance>)>, |
7453a54e | 56 | |
041b39d2 XL |
57 | // Maps from the node id of an item to the first inferred index |
58 | // used for its type & region parameters. | |
532ac7d7 | 59 | pub inferred_starts: HirIdMap<InferredIndex>, |
7453a54e | 60 | |
041b39d2 XL |
61 | // Maps from an InferredIndex to the term for that variable. |
62 | pub inferred_terms: Vec<VarianceTermPtr<'a>>, | |
7453a54e SL |
63 | } |
64 | ||
dc9dc135 XL |
65 | pub fn determine_parameters_to_be_inferred<'a, 'tcx>( |
66 | tcx: TyCtxt<'tcx>, | |
29967ef6 | 67 | arena: &'a DroplessArena, |
dc9dc135 | 68 | ) -> TermsContext<'a, 'tcx> { |
7453a54e | 69 | let mut terms_cx = TermsContext { |
3b2f2976 XL |
70 | tcx, |
71 | arena, | |
a1dfa0c6 | 72 | inferred_starts: Default::default(), |
041b39d2 | 73 | inferred_terms: vec![], |
7453a54e SL |
74 | |
75 | lang_items: lang_items(tcx), | |
7453a54e SL |
76 | }; |
77 | ||
0531ce1d XL |
78 | // See the following for a discussion on dep-graph management. |
79 | // | |
ba9703b0 XL |
80 | // - https://rustc-dev-guide.rust-lang.org/query.html |
81 | // - https://rustc-dev-guide.rust-lang.org/variance.html | |
c295e0f8 | 82 | tcx.hir().visit_all_item_likes(&mut terms_cx); |
7453a54e SL |
83 | |
84 | terms_cx | |
85 | } | |
86 | ||
dc9dc135 | 87 | fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> { |
ea8adc8c | 88 | let lang_items = tcx.lang_items(); |
5099ac24 | 89 | let all = [ |
ea8adc8c XL |
90 | (lang_items.phantom_data(), vec![ty::Covariant]), |
91 | (lang_items.unsafe_cell_type(), vec![ty::Invariant]), | |
dfeec247 | 92 | ]; |
7453a54e SL |
93 | |
94 | all.into_iter() // iterating over (Option<DefId>, Variance) | |
dfeec247 XL |
95 | .filter(|&(ref d, _)| d.is_some()) |
96 | .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance) | |
3dfed10e XL |
97 | .filter_map(|(d, v)| { |
98 | d.as_local().map(|d| tcx.hir().local_def_id_to_hir_id(d)).map(|n| (n, v)) | |
99 | }) // (HirId, Variance) | |
dfeec247 | 100 | .collect() |
7453a54e SL |
101 | } |
102 | ||
103 | impl<'a, 'tcx> TermsContext<'a, 'tcx> { | |
532ac7d7 | 104 | fn add_inferreds_for_item(&mut self, id: hir::HirId) { |
041b39d2 | 105 | let tcx = self.tcx; |
416331ca | 106 | let def_id = tcx.hir().local_def_id(id); |
041b39d2 | 107 | let count = tcx.generics_of(def_id).count(); |
7453a54e | 108 | |
041b39d2 XL |
109 | if count == 0 { |
110 | return; | |
7453a54e | 111 | } |
7453a54e | 112 | |
041b39d2 XL |
113 | // Record the start of this item's inferreds. |
114 | let start = self.inferred_terms.len(); | |
115 | let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none(); | |
7453a54e SL |
116 | assert!(newly_added); |
117 | ||
0731742a | 118 | // N.B., in the code below for writing the results back into the |
041b39d2 XL |
119 | // `CrateVariancesMap`, we rely on the fact that all inferreds |
120 | // for a particular item are assigned continuous indices. | |
7453a54e | 121 | |
041b39d2 | 122 | let arena = self.arena; |
dfeec247 XL |
123 | self.inferred_terms.extend( |
124 | (start..(start + count)).map(|i| &*arena.alloc(InferredTerm(InferredIndex(i)))), | |
125 | ); | |
7453a54e SL |
126 | } |
127 | } | |
128 | ||
476ff2be | 129 | impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { |
dfeec247 | 130 | fn visit_item(&mut self, item: &hir::Item<'_>) { |
6a06907d | 131 | debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(item.hir_id())); |
7453a54e | 132 | |
e74abb32 | 133 | match item.kind { |
dfeec247 | 134 | hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { |
6a06907d | 135 | self.add_inferreds_for_item(item.hir_id()); |
041b39d2 XL |
136 | |
137 | if let hir::VariantData::Tuple(..) = *struct_def { | |
532ac7d7 | 138 | self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap()); |
041b39d2 XL |
139 | } |
140 | } | |
141 | ||
8faf50e0 | 142 | hir::ItemKind::Enum(ref enum_def, _) => { |
6a06907d | 143 | self.add_inferreds_for_item(item.hir_id()); |
041b39d2 | 144 | |
dfeec247 | 145 | for variant in enum_def.variants { |
e1599b0c XL |
146 | if let hir::VariantData::Tuple(..) = variant.data { |
147 | self.add_inferreds_for_item(variant.data.ctor_hir_id().unwrap()); | |
041b39d2 XL |
148 | } |
149 | } | |
150 | } | |
151 | ||
8faf50e0 | 152 | hir::ItemKind::Fn(..) => { |
6a06907d | 153 | self.add_inferreds_for_item(item.hir_id()); |
7453a54e SL |
154 | } |
155 | ||
041b39d2 | 156 | _ => {} |
7453a54e SL |
157 | } |
158 | } | |
476ff2be | 159 | |
dfeec247 | 160 | fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { |
ba9703b0 | 161 | if let hir::TraitItemKind::Fn(..) = trait_item.kind { |
6a06907d | 162 | self.add_inferreds_for_item(trait_item.hir_id()); |
041b39d2 | 163 | } |
32a655c1 SL |
164 | } |
165 | ||
dfeec247 | 166 | fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { |
ba9703b0 | 167 | if let hir::ImplItemKind::Fn(..) = impl_item.kind { |
6a06907d | 168 | self.add_inferreds_for_item(impl_item.hir_id()); |
041b39d2 | 169 | } |
476ff2be | 170 | } |
fc512014 XL |
171 | |
172 | fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { | |
173 | if let hir::ForeignItemKind::Fn(..) = foreign_item.kind { | |
6a06907d | 174 | self.add_inferreds_for_item(foreign_item.hir_id()); |
fc512014 XL |
175 | } |
176 | } | |
7453a54e | 177 | } |