rustc_mir_transform/
add_subtyping_projections.rs

1use rustc_middle::mir::visit::MutVisitor;
2use rustc_middle::mir::*;
3use rustc_middle::ty::TyCtxt;
4
5use crate::patch::MirPatch;
6
7pub(super) struct Subtyper;
8
9struct SubTypeChecker<'a, 'tcx> {
10    tcx: TyCtxt<'tcx>,
11    patcher: MirPatch<'tcx>,
12    local_decls: &'a LocalDecls<'tcx>,
13}
14
15impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
16    fn tcx(&self) -> TyCtxt<'tcx> {
17        self.tcx
18    }
19
20    fn visit_assign(
21        &mut self,
22        place: &mut Place<'tcx>,
23        rvalue: &mut Rvalue<'tcx>,
24        location: Location,
25    ) {
26        // We don't need to do anything for deref temps as they are
27        // not part of the source code, but used for desugaring purposes.
28        if self.local_decls[place.local].is_deref_temp() {
29            return;
30        }
31        let mut place_ty = place.ty(self.local_decls, self.tcx).ty;
32        let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
33        // Not erasing this causes `Free Regions` errors in validator,
34        // when rval is `ReStatic`.
35        rval_ty = self.tcx.erase_regions_ty(rval_ty);
36        place_ty = self.tcx.erase_regions(place_ty);
37        if place_ty != rval_ty {
38            let temp = self
39                .patcher
40                .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
41            let new_place = Place::from(temp);
42            self.patcher.add_assign(location, new_place, rvalue.clone());
43            let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx);
44            *rvalue = Rvalue::Use(Operand::Move(subtyped));
45        }
46    }
47}
48
49// Aim here is to do this kind of transformation:
50//
51// let place: place_ty = rval;
52// // gets transformed to
53// let temp: rval_ty = rval;
54// let place: place_ty = temp as place_ty;
55impl<'tcx> crate::MirPass<'tcx> for Subtyper {
56    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
57        let patch = MirPatch::new(body);
58        let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
59
60        for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
61            checker.visit_basic_block_data(bb, data);
62        }
63        checker.patcher.apply(body);
64    }
65
66    fn is_required(&self) -> bool {
67        true
68    }
69}