Skip to main content

rustc_mir_transform/
post_analysis_normalize.rs

1//! Normalizes MIR in `TypingMode::PostAnalysis` mode, most notably revealing
2//! its opaques. We also only normalize specializable associated items once in
3//! `PostAnalysis` mode.
4
5use rustc_middle::mir::visit::*;
6use rustc_middle::mir::*;
7use rustc_middle::ty::{self, Ty, TyCtxt};
8
9use crate::PassPolicy;
10
11pub(super) struct PostAnalysisNormalize;
12
13impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
14    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
15        // FIXME(#132279): This is used during the phase transition from analysis
16        // to runtime, so we have to manually specify the correct typing mode.
17        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
18        PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
19    }
20
21    fn policy(&self, _sess: &rustc_session::Session) -> PassPolicy {
22        // Reveals opaque types and normalizes MIR while transitioning to the runtime dialect.
23        PassPolicy::Required
24    }
25}
26
27struct PostAnalysisNormalizeVisitor<'tcx> {
28    tcx: TyCtxt<'tcx>,
29    typing_env: ty::TypingEnv<'tcx>,
30}
31
32impl<'tcx> MutVisitor<'tcx> for PostAnalysisNormalizeVisitor<'tcx> {
33    #[inline]
34    fn tcx(&self) -> TyCtxt<'tcx> {
35        self.tcx
36    }
37
38    #[inline]
39    fn visit_place(
40        &mut self,
41        place: &mut Place<'tcx>,
42        _context: PlaceContext,
43        _location: Location,
44    ) {
45        if !self.tcx.next_trait_solver_globally() {
46            // `OpaqueCast` projections are only needed if there are opaque types on which projections
47            // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
48            // hidden types, so we don't need these projections anymore.
49            //
50            // Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
51            if place.projection.iter().any(|elem| matches!(elem, ProjectionElem::OpaqueCast(_))) {
52                place.projection = self.tcx.mk_place_elems(
53                    &place
54                        .projection
55                        .into_iter()
56                        .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
57                        .collect::<Vec<_>>(),
58                );
59            };
60        }
61        self.super_place(place, _context, _location);
62    }
63
64    #[inline]
65    fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
66        // We have to use `try_normalize_erasing_regions` here, since it's
67        // possible that we visit impossible-to-satisfy where clauses here,
68        // see #91745
69        if let Ok(c) = self.tcx.try_normalize_erasing_regions(
70            self.typing_env,
71            ty::set_aliases_to_non_rigid(self.tcx, constant.const_),
72        ) {
73            constant.const_ = c;
74        }
75        self.super_const_operand(constant, location);
76    }
77
78    #[inline]
79    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
80        // We have to use `try_normalize_erasing_regions` here, since it's
81        // possible that we visit impossible-to-satisfy where clauses here,
82        // see #91745
83        if let Ok(t) = self.tcx.try_normalize_erasing_regions(
84            self.typing_env,
85            ty::set_aliases_to_non_rigid(self.tcx, *ty),
86        ) {
87            *ty = t;
88        }
89    }
90
91    #[inline]
92    fn visit_args(&mut self, args: &mut ty::GenericArgsRef<'tcx>, _: Location) {
93        if let Ok(a) = self.tcx.try_normalize_erasing_regions(
94            self.typing_env,
95            ty::set_aliases_to_non_rigid(self.tcx, *args),
96        ) {
97            *args = a;
98        }
99    }
100}