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
9pub(super) struct PostAnalysisNormalize;
10
11impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
12    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
13        // FIXME(#132279): This is used during the phase transition from analysis
14        // to runtime, so we have to manually specify the correct typing mode.
15        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
16        PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
17    }
18
19    fn is_required(&self) -> bool {
20        true
21    }
22}
23
24struct PostAnalysisNormalizeVisitor<'tcx> {
25    tcx: TyCtxt<'tcx>,
26    typing_env: ty::TypingEnv<'tcx>,
27}
28
29impl<'tcx> MutVisitor<'tcx> for PostAnalysisNormalizeVisitor<'tcx> {
30    #[inline]
31    fn tcx(&self) -> TyCtxt<'tcx> {
32        self.tcx
33    }
34
35    #[inline]
36    fn visit_place(
37        &mut self,
38        place: &mut Place<'tcx>,
39        _context: PlaceContext,
40        _location: Location,
41    ) {
42        if !self.tcx.next_trait_solver_globally() {
43            // `OpaqueCast` projections are only needed if there are opaque types on which projections
44            // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
45            // hidden types, so we don't need these projections anymore.
46            //
47            // Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
48            if place.projection.iter().any(|elem| matches!(elem, ProjectionElem::OpaqueCast(_))) {
49                place.projection = self.tcx.mk_place_elems(
50                    &place
51                        .projection
52                        .into_iter()
53                        .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
54                        .collect::<Vec<_>>(),
55                );
56            };
57        }
58        self.super_place(place, _context, _location);
59    }
60
61    #[inline]
62    fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
63        // We have to use `try_normalize_erasing_regions` here, since it's
64        // possible that we visit impossible-to-satisfy where clauses here,
65        // see #91745
66        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.typing_env, constant.const_) {
67            constant.const_ = c;
68        }
69        self.super_const_operand(constant, location);
70    }
71
72    #[inline]
73    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
74        // We have to use `try_normalize_erasing_regions` here, since it's
75        // possible that we visit impossible-to-satisfy where clauses here,
76        // see #91745
77        if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.typing_env, *ty) {
78            *ty = t;
79        }
80    }
81}