rustc_mir_transform/
add_subtyping_projections.rs1use 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 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 rval_ty = self.tcx.erase_and_anonymize_regions(rval_ty);
36 place_ty = self.tcx.erase_and_anonymize_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 *rvalue = Rvalue::Cast(CastKind::Subtype, Operand::Move(new_place), place_ty);
44 }
45 }
46}
47
48impl<'tcx> crate::MirPass<'tcx> for Subtyper {
55 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
56 let patch = MirPatch::new(body);
57 let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
58
59 for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
60 checker.visit_basic_block_data(bb, data);
61 }
62 checker.patcher.apply(body);
63 }
64
65 fn is_required(&self) -> bool {
66 true
67 }
68}