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).
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
12 use rustc_arena
::DroplessArena
;
13 use rustc_hir
::def
::DefKind
;
14 use rustc_hir
::def_id
::{LocalDefId, LocalDefIdMap}
;
15 use rustc_middle
::ty
::{self, TyCtxt}
;
18 use self::VarianceTerm
::*;
20 pub type VarianceTermPtr
<'a
> = &'a VarianceTerm
<'a
>;
22 #[derive(Copy, Clone, Debug)]
23 pub struct InferredIndex(pub usize);
25 #[derive(Copy, Clone)]
26 pub enum VarianceTerm
<'a
> {
27 ConstantTerm(ty
::Variance
),
28 TransformTerm(VarianceTermPtr
<'a
>, VarianceTermPtr
<'a
>),
29 InferredTerm(InferredIndex
),
32 impl<'a
> fmt
::Debug
for VarianceTerm
<'a
> {
33 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
35 ConstantTerm(c1
) => write
!(f
, "{:?}", c1
),
36 TransformTerm(v1
, v2
) => write
!(f
, "({:?} \u{00D7} {:?})", v1
, v2
),
37 InferredTerm(id
) => write
!(f
, "[{}]", {
38 let InferredIndex(i
) = id
;
45 // The first pass over the crate simply builds up the set of inferreds.
47 pub struct TermsContext
<'a
, 'tcx
> {
48 pub tcx
: TyCtxt
<'tcx
>,
49 pub arena
: &'a DroplessArena
,
51 // For marker types, UnsafeCell, and other lang items where
52 // variance is hardcoded, records the item-id and the hardcoded
54 pub lang_items
: Vec
<(LocalDefId
, Vec
<ty
::Variance
>)>,
56 // Maps from the node id of an item to the first inferred index
57 // used for its type & region parameters.
58 pub inferred_starts
: LocalDefIdMap
<InferredIndex
>,
60 // Maps from an InferredIndex to the term for that variable.
61 pub inferred_terms
: Vec
<VarianceTermPtr
<'a
>>,
64 pub fn determine_parameters_to_be_inferred
<'a
, 'tcx
>(
66 arena
: &'a DroplessArena
,
67 ) -> TermsContext
<'a
, 'tcx
> {
68 let mut terms_cx
= TermsContext
{
71 inferred_starts
: Default
::default(),
72 inferred_terms
: vec
![],
74 lang_items
: lang_items(tcx
),
77 // See the following for a discussion on dep-graph management.
79 // - https://rustc-dev-guide.rust-lang.org/query.html
80 // - https://rustc-dev-guide.rust-lang.org/variance.html
81 let crate_items
= tcx
.hir_crate_items(());
83 for def_id
in crate_items
.definitions() {
84 debug
!("add_inferreds for item {:?}", def_id
);
86 let def_kind
= tcx
.def_kind(def_id
);
89 DefKind
::Struct
| DefKind
::Union
| DefKind
::Enum
=> {
90 terms_cx
.add_inferreds_for_item(def_id
);
92 let adt
= tcx
.adt_def(def_id
);
93 for variant
in adt
.variants() {
94 if let Some(ctor
) = variant
.ctor_def_id
{
95 terms_cx
.add_inferreds_for_item(ctor
.expect_local());
99 DefKind
::Fn
| DefKind
::AssocFn
=> terms_cx
.add_inferreds_for_item(def_id
),
107 fn lang_items(tcx
: TyCtxt
<'_
>) -> Vec
<(LocalDefId
, Vec
<ty
::Variance
>)> {
108 let lang_items
= tcx
.lang_items();
110 (lang_items
.phantom_data(), vec
![ty
::Covariant
]),
111 (lang_items
.unsafe_cell_type(), vec
![ty
::Invariant
]),
114 all
.into_iter() // iterating over (Option<DefId>, Variance)
115 .filter_map(|(d
, v
)| {
116 let def_id
= d?
.as_local()?
; // LocalDefId
122 impl<'a
, 'tcx
> TermsContext
<'a
, 'tcx
> {
123 fn add_inferreds_for_item(&mut self, def_id
: LocalDefId
) {
125 let count
= tcx
.generics_of(def_id
).count();
131 // Record the start of this item's inferreds.
132 let start
= self.inferred_terms
.len();
133 let newly_added
= self.inferred_starts
.insert(def_id
, InferredIndex(start
)).is_none();
134 assert
!(newly_added
);
136 // N.B., in the code below for writing the results back into the
137 // `CrateVariancesMap`, we rely on the fact that all inferreds
138 // for a particular item are assigned continuous indices.
140 let arena
= self.arena
;
141 self.inferred_terms
.extend(
142 (start
..(start
+ count
)).map(|i
| &*arena
.alloc(InferredTerm(InferredIndex(i
)))),