rustc_borrowck/
renumber.rs

1use rustc_index::IndexSlice;
2use rustc_infer::infer::NllRegionVariableOrigin;
3use rustc_middle::mir::visit::{MutVisitor, TyContext};
4use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
5use rustc_middle::ty::fold::fold_regions;
6use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable};
7use rustc_span::Symbol;
8use tracing::{debug, instrument};
9
10use crate::BorrowckInferCtxt;
11
12/// Replaces all free regions appearing in the MIR with fresh
13/// inference variables, returning the number of variables created.
14#[instrument(skip(infcx, body, promoted), level = "debug")]
15pub(crate) fn renumber_mir<'tcx>(
16    infcx: &BorrowckInferCtxt<'tcx>,
17    body: &mut Body<'tcx>,
18    promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
19) {
20    debug!(?body.arg_count);
21
22    let mut renumberer = RegionRenumberer { infcx };
23
24    for body in promoted.iter_mut() {
25        renumberer.visit_body(body);
26    }
27
28    renumberer.visit_body(body);
29}
30
31// The fields are used only for debugging output in `sccs_info`.
32#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
33pub(crate) enum RegionCtxt {
34    Location(Location),
35    TyContext(TyContext),
36    Free(Symbol),
37    LateBound(Symbol),
38    Existential(Option<Symbol>),
39    Placeholder(Symbol),
40    Unknown,
41}
42
43impl RegionCtxt {
44    /// Used to determine the representative of a component in the strongly connected
45    /// constraint graph
46    pub(crate) fn preference_value(self) -> usize {
47        match self {
48            RegionCtxt::Unknown => 1,
49            RegionCtxt::Existential(None) => 2,
50            RegionCtxt::Existential(Some(_)) | RegionCtxt::Free(_) => 2,
51            RegionCtxt::Location(_) => 3,
52            RegionCtxt::TyContext(_) => 4,
53            _ => 5,
54        }
55    }
56}
57
58struct RegionRenumberer<'a, 'tcx> {
59    infcx: &'a BorrowckInferCtxt<'tcx>,
60}
61
62impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
63    /// Replaces all regions appearing in `value` with fresh inference
64    /// variables.
65    fn renumber_regions<T, F>(&mut self, value: T, region_ctxt_fn: F) -> T
66    where
67        T: TypeFoldable<TyCtxt<'tcx>>,
68        F: Fn() -> RegionCtxt,
69    {
70        let origin = NllRegionVariableOrigin::Existential { from_forall: false };
71        fold_regions(self.infcx.tcx, value, |_region, _depth| {
72            self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
73        })
74    }
75}
76
77impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
78    fn tcx(&self) -> TyCtxt<'tcx> {
79        self.infcx.tcx
80    }
81
82    #[instrument(skip(self), level = "debug")]
83    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
84        if matches!(ty_context, TyContext::ReturnTy(_)) {
85            // We will renumber the return ty when called again with `TyContext::LocalDecl`
86            return;
87        }
88        *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context));
89
90        debug!(?ty);
91    }
92
93    #[instrument(skip(self), level = "debug")]
94    fn visit_args(&mut self, args: &mut GenericArgsRef<'tcx>, location: Location) {
95        *args = self.renumber_regions(*args, || RegionCtxt::Location(location));
96
97        debug!(?args);
98    }
99
100    #[instrument(skip(self), level = "debug")]
101    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
102        let old_region = *region;
103        *region = self.renumber_regions(old_region, || RegionCtxt::Location(location));
104
105        debug!(?region);
106    }
107
108    #[instrument(skip(self), level = "debug")]
109    fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, location: Location) {
110        let old_ct = *ct;
111        *ct = self.renumber_regions(old_ct, || RegionCtxt::Location(location));
112
113        debug!(?ct);
114    }
115
116    #[instrument(skip(self), level = "debug")]
117    fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
118        let const_ = constant.const_;
119        constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
120        debug!("constant: {:#?}", constant);
121    }
122}