1 // Copyright 2013 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.
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.
13 // Terms are structured as a straightforward tree. Rather than rely on
14 // GC, we allocate terms out of a bounded arena (the lifetime of this
15 // arena is the lifetime 'a that is threaded around).
17 // We assign a unique index to each type/region parameter whose variance
18 // is to be inferred. We refer to such variables as "inferreds". An
19 // `InferredIndex` is a newtype'd int representing the index of such
22 use arena::TypedArena;
23 use rustc::ty::{self, TyCtxt};
28 use rustc::hir::itemlikevisit::ItemLikeVisitor;
29 use util::nodemap::NodeMap;
31 use self::VarianceTerm::*;
33 pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
35 #[derive(Copy, Clone, Debug)]
36 pub struct InferredIndex(pub usize);
38 #[derive(Copy, Clone)]
39 pub enum VarianceTerm<'a> {
40 ConstantTerm(ty::Variance),
41 TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>),
42 InferredTerm(InferredIndex),
45 impl<'a> fmt::Debug for VarianceTerm<'a> {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 ConstantTerm(c1) => write!(f, "{:?}", c1),
49 TransformTerm(v1, v2) => write!(f, "({:?} \u{00D7} {:?})", v1, v2),
52 let InferredIndex(i) = id;
60 // The first pass over the crate simply builds up the set of inferreds.
62 pub struct TermsContext<'a, 'tcx: 'a> {
63 pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
64 pub arena: &'a TypedArena<VarianceTerm<'a>>,
66 pub empty_variances: Rc<Vec<ty::Variance>>,
68 // For marker types, UnsafeCell, and other lang items where
69 // variance is hardcoded, records the item-id and the hardcoded
71 pub lang_items: Vec<(ast::NodeId, Vec<ty::Variance>)>,
73 // Maps from the node id of a type/generic parameter to the
74 // corresponding inferred index.
75 pub inferred_map: NodeMap<InferredIndex>,
77 // Maps from an InferredIndex to the info for that variable.
78 pub inferred_infos: Vec<InferredInfo<'a>>,
81 pub struct InferredInfo<'a> {
82 pub item_id: ast::NodeId,
84 pub param_id: ast::NodeId,
85 pub term: VarianceTermPtr<'a>,
87 // Initial value to use for this parameter when inferring
88 // variance. For most parameters, this is Bivariant. But for lang
89 // items and input type parameters on traits, it is different.
90 pub initial_variance: ty::Variance,
93 pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
94 arena: &'a mut TypedArena<VarianceTerm<'a>>)
95 -> TermsContext<'a, 'tcx> {
96 let mut terms_cx = TermsContext {
99 inferred_map: NodeMap(),
100 inferred_infos: Vec::new(),
102 lang_items: lang_items(tcx),
104 // cache and share the variance struct used for items with
105 // no type/region parameters
106 empty_variances: Rc::new(vec![]),
109 // See README.md for a discussion on dep-graph management.
110 tcx.hir.krate().visit_all_item_likes(&mut terms_cx);
115 fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec<ty::Variance>)> {
117 (tcx.lang_items.phantom_data(), vec![ty::Covariant]),
118 (tcx.lang_items.unsafe_cell_type(), vec![ty::Invariant]),
121 (tcx.lang_items.covariant_type(), vec![ty::Covariant]),
122 (tcx.lang_items.contravariant_type(), vec![ty::Contravariant]),
123 (tcx.lang_items.invariant_type(), vec![ty::Invariant]),
124 (tcx.lang_items.covariant_lifetime(), vec![ty::Covariant]),
125 (tcx.lang_items.contravariant_lifetime(), vec![ty::Contravariant]),
126 (tcx.lang_items.invariant_lifetime(), vec![ty::Invariant]),
130 all.into_iter() // iterating over (Option<DefId>, Variance)
131 .filter(|&(ref d,_)| d.is_some())
132 .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance)
133 .filter_map(|(d, v)| tcx.hir.as_local_node_id(d).map(|n| (n, v))) // (NodeId, Variance)
137 impl<'a, 'tcx> TermsContext<'a, 'tcx> {
138 fn add_inferreds_for_item(&mut self,
139 item_id: ast::NodeId,
140 generics: &hir::Generics) {
141 //! Add "inferreds" for the generic parameters declared on this
142 //! item. This has a lot of annoying parameters because we are
143 //! trying to drive this from the AST, rather than the
144 //! ty::Generics, so that we can get span info -- but this
145 //! means we must accommodate syntactic distinctions.
148 // NB: In the code below for writing the results back into the
149 // `CrateVariancesMap`, we rely on the fact that all inferreds
150 // for a particular item are assigned continuous indices.
152 for (p, i) in generics.lifetimes.iter().zip(0..) {
153 let id = p.lifetime.id;
154 self.add_inferred(item_id, i, id);
157 for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) {
158 self.add_inferred(item_id, i, p.id);
162 fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) {
163 let inf_index = InferredIndex(self.inferred_infos.len());
164 let term = self.arena.alloc(InferredTerm(inf_index));
165 let initial_variance = self.pick_initial_variance(item_id, index);
166 self.inferred_infos.push(InferredInfo {
171 initial_variance: initial_variance,
173 let newly_added = self.inferred_map.insert(param_id, inf_index).is_none();
174 assert!(newly_added);
176 debug!("add_inferred(item_path={}, \
181 initial_variance={:?})",
182 self.tcx.item_path_str(self.tcx.hir.local_def_id(item_id)),
190 fn pick_initial_variance(&self, item_id: ast::NodeId, index: usize) -> ty::Variance {
191 match self.lang_items.iter().find(|&&(n, _)| n == item_id) {
192 Some(&(_, ref variances)) => variances[index],
193 None => ty::Bivariant,
197 pub fn num_inferred(&self) -> usize {
198 self.inferred_infos.len()
202 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
203 fn visit_item(&mut self, item: &hir::Item) {
204 debug!("add_inferreds for item {}",
205 self.tcx.hir.node_to_string(item.id));
208 hir::ItemEnum(_, ref generics) |
209 hir::ItemStruct(_, ref generics) |
210 hir::ItemUnion(_, ref generics) => {
211 self.add_inferreds_for_item(item.id, generics);
215 hir::ItemExternCrate(_) |
217 hir::ItemDefaultImpl(..) |
219 hir::ItemStatic(..) |
223 hir::ItemForeignMod(..) |
224 hir::ItemGlobalAsm(..) |
225 hir::ItemTy(..) => {}
229 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
232 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {