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