Skip to main content

rustc_hir_analysis/variance/
terms.rs

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
12use 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(#[automatically_derived]
impl ::core::marker::Copy for InferredIndex { }Copy, #[automatically_derived]
impl ::core::clone::Clone for InferredIndex {
    #[inline]
    fn clone(&self) -> InferredIndex {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for InferredIndex {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "InferredIndex",
            &&self.0)
    }
}Debug)]
25pub(crate) struct InferredIndex(pub usize);
26
27#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for VarianceTerm<'a> { }Copy, #[automatically_derived]
impl<'a> ::core::clone::Clone for VarianceTerm<'a> {
    #[inline]
    fn clone(&self) -> VarianceTerm<'a> {
        let _: ::core::clone::AssertParamIsClone<ty::Variance>;
        let _: ::core::clone::AssertParamIsClone<VarianceTermPtr<'a>>;
        let _: ::core::clone::AssertParamIsClone<VarianceTermPtr<'a>>;
        let _: ::core::clone::AssertParamIsClone<InferredIndex>;
        *self
    }
}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) => f.write_fmt(format_args!("{0:?}", c1))write!(f, "{c1:?}"),
38            TransformTerm(v1, v2) => f.write_fmt(format_args!("({0:?} × {1:?})", v1, v2))write!(f, "({v1:?} \u{00D7} {v2:?})"),
39            InferredTerm(id) => f.write_fmt(format_args!("[{0}]", { let InferredIndex(i) = id; i }))write!(f, "[{}]", {
40                let InferredIndex(i) = id;
41                i
42            }),
43        }
44    }
45}
46
47// The first pass over the crate simply builds up the set of inferreds.
48
49pub(crate) struct TermsContext<'a, 'tcx> {
50    pub tcx: TyCtxt<'tcx>,
51    pub arena: &'a DroplessArena,
52
53    /// For marker types, `UnsafeCell`, and other lang items where
54    /// variance is hardcoded, records the item-id and the hardcoded
55    /// variance.
56    pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>,
57
58    /// Maps from the node id of an item to the first inferred index
59    /// used for its type & region parameters.
60    pub inferred_starts: LocalDefIdMap<InferredIndex>,
61
62    /// Maps from an InferredIndex to the term for that variable.
63    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: ::alloc::vec::Vec::new()vec![],
75
76        lang_items: lang_items(tcx),
77    };
78
79    // See the following for a discussion on dep-graph management.
80    //
81    // - https://rustc-dev-guide.rust-lang.org/query.html
82    // - https://rustc-dev-guide.rust-lang.org/variance.html
83    let crate_items = tcx.hir_crate_items(());
84
85    for def_id in crate_items.definitions() {
86        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/variance/terms.rs:86",
                        "rustc_hir_analysis::variance::terms",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/variance/terms.rs"),
                        ::tracing_core::__macro_support::Option::Some(86u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::variance::terms"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("add_inferreds for item {0:?}",
                                                    def_id) as &dyn Value))])
            });
    } else { ; }
};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(), <[_]>::into_vec(::alloc::boxed::box_new([ty::Covariant]))vec![ty::Covariant]),
116        (lang_items.unsafe_cell_type(), <[_]>::into_vec(::alloc::boxed::box_new([ty::Invariant]))vec![ty::Invariant]),
117    ];
118
119    all.into_iter() // iterating over (Option<DefId>, Variance)
120        .filter_map(|(d, v)| {
121            let def_id = d?.as_local()?; // LocalDefId
122            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        // Record the start of this item's inferreds.
137        let start = self.inferred_terms.len();
138        let newly_added = self.inferred_starts.insert(def_id, InferredIndex(start)).is_none();
139        if !newly_added { ::core::panicking::panic("assertion failed: newly_added") };assert!(newly_added);
140
141        // N.B., in the code below for writing the results back into the
142        // `CrateVariancesMap`, we rely on the fact that all inferreds
143        // for a particular item are assigned continuous indices.
144
145        let arena = self.arena;
146        self.inferred_terms.extend(
147            (start..(start + count)).map(|i| &*arena.alloc(InferredTerm(InferredIndex(i)))),
148        );
149    }
150}