rustc_hir_analysis/variance/
terms.rs
1use std::fmt;
13
14use rustc_arena::DroplessArena;
15use rustc_hir::def::DefKind;
16use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
17use rustc_middle::ty::{self, TyCtxt};
18use tracing::debug;
19
20use self::VarianceTerm::*;
21
22pub(crate) type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
23
24#[derive(Copy, Clone, Debug)]
25pub(crate) struct InferredIndex(pub usize);
26
27#[derive(Copy, Clone)]
28pub(crate) enum VarianceTerm<'a> {
29 ConstantTerm(ty::Variance),
30 TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>),
31 InferredTerm(InferredIndex),
32}
33
34impl<'a> fmt::Debug for VarianceTerm<'a> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match *self {
37 ConstantTerm(c1) => write!(f, "{c1:?}"),
38 TransformTerm(v1, v2) => write!(f, "({v1:?} \u{00D7} {v2:?})"),
39 InferredTerm(id) => write!(f, "[{}]", {
40 let InferredIndex(i) = id;
41 i
42 }),
43 }
44 }
45}
46
47pub(crate) struct TermsContext<'a, 'tcx> {
50 pub tcx: TyCtxt<'tcx>,
51 pub arena: &'a DroplessArena,
52
53 pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>,
57
58 pub inferred_starts: LocalDefIdMap<InferredIndex>,
61
62 pub inferred_terms: Vec<VarianceTermPtr<'a>>,
64}
65
66pub(crate) fn determine_parameters_to_be_inferred<'a, 'tcx>(
67 tcx: TyCtxt<'tcx>,
68 arena: &'a DroplessArena,
69) -> TermsContext<'a, 'tcx> {
70 let mut terms_cx = TermsContext {
71 tcx,
72 arena,
73 inferred_starts: Default::default(),
74 inferred_terms: vec![],
75
76 lang_items: lang_items(tcx),
77 };
78
79 let crate_items = tcx.hir_crate_items(());
84
85 for def_id in crate_items.definitions() {
86 debug!("add_inferreds for item {:?}", def_id);
87
88 let def_kind = tcx.def_kind(def_id);
89
90 match def_kind {
91 DefKind::Struct | DefKind::Union | DefKind::Enum => {
92 terms_cx.add_inferreds_for_item(def_id);
93
94 let adt = tcx.adt_def(def_id);
95 for variant in adt.variants() {
96 if let Some(ctor_def_id) = variant.ctor_def_id() {
97 terms_cx.add_inferreds_for_item(ctor_def_id.expect_local());
98 }
99 }
100 }
101 DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
102 DefKind::TyAlias if tcx.type_alias_is_lazy(def_id) => {
103 terms_cx.add_inferreds_for_item(def_id)
104 }
105 _ => {}
106 }
107 }
108
109 terms_cx
110}
111
112fn lang_items(tcx: TyCtxt<'_>) -> Vec<(LocalDefId, Vec<ty::Variance>)> {
113 let lang_items = tcx.lang_items();
114 let all = [
115 (lang_items.phantom_data(), vec![ty::Covariant]),
116 (lang_items.unsafe_cell_type(), vec![ty::Invariant]),
117 ];
118
119 all.into_iter() .filter_map(|(d, v)| {
121 let def_id = d?.as_local()?; Some((def_id, v))
123 })
124 .collect()
125}
126
127impl<'a, 'tcx> TermsContext<'a, 'tcx> {
128 fn add_inferreds_for_item(&mut self, def_id: LocalDefId) {
129 let tcx = self.tcx;
130 let count = tcx.generics_of(def_id).count();
131
132 if count == 0 {
133 return;
134 }
135
136 let start = self.inferred_terms.len();
138 let newly_added = self.inferred_starts.insert(def_id, InferredIndex(start)).is_none();
139 assert!(newly_added);
140
141 let arena = self.arena;
146 self.inferred_terms.extend(
147 (start..(start + count)).map(|i| &*arena.alloc(InferredTerm(InferredIndex(i)))),
148 );
149 }
150}