Skip to main content

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