]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/variance/terms.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / variance / terms.rs
CommitLineData
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 12use rustc_arena::DroplessArena;
dfeec247
XL
13use rustc_hir as hir;
14use rustc_hir::itemlikevisit::ItemLikeVisitor;
15use rustc_hir::HirIdMap;
ba9703b0 16use rustc_middle::ty::{self, TyCtxt};
7453a54e 17use std::fmt;
7453a54e
SL
18
19use self::VarianceTerm::*;
7453a54e
SL
20
21pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
22
23#[derive(Copy, Clone, Debug)]
24pub struct InferredIndex(pub usize);
25
26#[derive(Copy, Clone)]
27pub enum VarianceTerm<'a> {
28 ConstantTerm(ty::Variance),
29 TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>),
30 InferredTerm(InferredIndex),
31}
32
33impl<'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
48pub 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
65pub 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 87fn 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
103impl<'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 129impl<'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}