rustc_mir_transform/
post_analysis_normalize.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Normalizes MIR in `TypingMode::PostAnalysis` mode, most notably revealing
//! its opaques. We also only normalize specializable associated items once in
//! `PostAnalysis` mode.

use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};

pub(super) struct PostAnalysisNormalize;

impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        // FIXME(#132279): This is used during the phase transition from analysis
        // to runtime, so we have to manually specify the correct typing mode.
        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
        PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
    }
}

struct PostAnalysisNormalizeVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    typing_env: ty::TypingEnv<'tcx>,
}

impl<'tcx> MutVisitor<'tcx> for PostAnalysisNormalizeVisitor<'tcx> {
    #[inline]
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    #[inline]
    fn visit_place(
        &mut self,
        place: &mut Place<'tcx>,
        _context: PlaceContext,
        _location: Location,
    ) {
        // Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
        if place.projection.iter().all(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) {
            return;
        }
        // `OpaqueCast` projections are only needed if there are opaque types on which projections
        // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
        // hidden types, so we don't need these projections anymore.
        place.projection = self.tcx.mk_place_elems(
            &place
                .projection
                .into_iter()
                .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
                .collect::<Vec<_>>(),
        );
        self.super_place(place, _context, _location);
    }

    #[inline]
    fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
        // We have to use `try_normalize_erasing_regions` here, since it's
        // possible that we visit impossible-to-satisfy where clauses here,
        // see #91745
        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.typing_env, constant.const_) {
            constant.const_ = c;
        }
        self.super_const_operand(constant, location);
    }

    #[inline]
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
        // We have to use `try_normalize_erasing_regions` here, since it's
        // possible that we visit impossible-to-satisfy where clauses here,
        // see #91745
        if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.typing_env, *ty) {
            *ty = t;
        }
    }
}