about summary refs log tree commit diff
diff options
context:
space:
mode:
authorouz-a <ouz.agz@gmail.com>2023-08-16 08:43:30 +0300
committerMark Rousskov <mark.simulacrum@gmail.com>2023-12-04 09:55:14 -0500
commitfa7a3184b49946e6bc6e77c0d79ed231ea29c69a (patch)
treee14c5d8170bba2b5aac4b6727b66041cfcd3c20b
parent97dcd63d17a395002db9df0e0b9801b327acaaea (diff)
downloadrust-fa7a3184b49946e6bc6e77c0d79ed231ea29c69a.tar.gz
rust-fa7a3184b49946e6bc6e77c0d79ed231ea29c69a.zip
subtyping_projections
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs3
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs24
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs2
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs3
-rw-r--r--compiler/rustc_mir_transform/src/add_subtyping_projections.rs57
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs1
-rw-r--r--tests/mir-opt/mir_subtyping.main.Subtyper.diff262
-rw-r--r--tests/mir-opt/mir_subtyping.rs43
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir3
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir3
28 files changed, 431 insertions, 5 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index cfd794e9e00..ee352e911d3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2827,6 +2827,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         }
                         ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::Subslice { .. }
+                        | ProjectionElem::Subtype(_)
                         | ProjectionElem::Index(_) => kind,
                     },
                     place_ty.projection_ty(tcx, elem),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 8c4fa917f9d..745949d3ff0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -242,6 +242,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ProjectionElem::Downcast(..) if opt.including_downcast => return None,
                 ProjectionElem::Downcast(..) => (),
                 ProjectionElem::OpaqueCast(..) => (),
+                ProjectionElem::Subtype(..) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
                     if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -317,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
                 ProjectionElem::Deref
                 | ProjectionElem::Index(..)
+                | ProjectionElem::Subtype(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
                     PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a0edeec59d0..8ca57383e82 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -159,6 +159,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     [
                         ..,
                         ProjectionElem::Index(_)
+                        | ProjectionElem::Subtype(_)
                         | ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::OpaqueCast { .. }
                         | ProjectionElem::Subslice { .. }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index abf9811c50b..1d17df8b79a 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1803,6 +1803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         for (place_base, elem) in place.iter_projections().rev() {
             match elem {
                 ProjectionElem::Index(_/*operand*/) |
+                ProjectionElem::Subtype(_) |
                 ProjectionElem::OpaqueCast(_) |
                 ProjectionElem::ConstantIndex { .. } |
                 // assigning to P[i] requires P to be valid.
@@ -2191,6 +2192,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ProjectionElem::Index(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
+                    | ProjectionElem::Subtype(..)
                     | ProjectionElem::OpaqueCast { .. }
                     | ProjectionElem::Downcast(..) => {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index a0fcdcd1f5e..fcf45179b9d 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -243,6 +243,7 @@ fn place_components_conflict<'tcx>(
                 }
 
                 (ProjectionElem::Deref, _, Deep)
+                | (ProjectionElem::Subtype(_), _, _)
                 | (ProjectionElem::Deref, _, AccessDepth::Drop)
                 | (ProjectionElem::Field { .. }, _, _)
                 | (ProjectionElem::Index { .. }, _, _)
@@ -359,6 +360,7 @@ fn place_projection_conflict<'tcx>(
         (
             ProjectionElem::Index(..),
             ProjectionElem::Index(..)
+            | ProjectionElem::Subtype(..)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. },
         )
@@ -503,6 +505,7 @@ fn place_projection_conflict<'tcx>(
             debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
             Overlap::EqualOrDisjoint
         }
+        (ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint,
         (
             ProjectionElem::Deref
             | ProjectionElem::Field(..)
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 6f281349863..72c22d217b4 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -89,6 +89,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                             cursor = cursor_base;
                             continue 'cursor;
                         }
+                        ProjectionElem::Subtype(..) => continue 'cursor,
                         ProjectionElem::Deref => {
                             // (handled below)
                         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d2ce6185584..33687792701 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -621,6 +621,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
                 }))
             }
+            ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty),
             ProjectionElem::Index(i) => {
                 let index_ty = Place::from(i).ty(self.body(), tcx).ty;
                 if index_ty != tcx.types.usize {
@@ -2556,6 +2557,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
                 }
                 ProjectionElem::Field(..)
+                | ProjectionElem::Subtype(..)
                 | ProjectionElem::Downcast(..)
                 | ProjectionElem::OpaqueCast(..)
                 | ProjectionElem::Index(..)
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 6d55fdc3074..06780567fb8 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -872,6 +872,9 @@ pub(crate) fn codegen_place<'tcx>(
 
     for elem in place.projection {
         match elem {
+            PlaceElem::Subtype(_) => {
+                continue;
+            }
             PlaceElem::Deref => {
                 cplace = cplace.place_deref(fx);
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index f775711f870..9ff73aab907 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -499,6 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     subslice
                 }
                 mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+                mir::ProjectionElem::Subtype(_) => continue,
             };
         }
         debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index a32ea204f98..b33396de33b 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -665,6 +665,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?;
         // Using `try_fold` turned out to be bad for performance, hence the loop.
         for elem in mir_place.projection.iter() {
+            if elem.is_subtype() {
+                continue;
+            }
             op = self.project(&op, elem)?
         }
 
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index f462c13816e..3c24381f93d 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -332,6 +332,7 @@ where
                 self.project_constant_index(base, offset, min_length, from_end)?
             }
             Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?,
+            Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?,
         })
     }
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index c26d6012412..8c2346c4efd 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -664,6 +664,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             | ProjectionElem::Downcast(..)
             | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Subtype(..)
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {}
         }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 34e9b76c484..de3186a53c1 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -306,6 +306,7 @@ where
             ProjectionElem::Index(index) if in_local(index) => return true,
 
             ProjectionElem::Deref
+            | ProjectionElem::Subtype(_)
             | ProjectionElem::Field(_, _)
             | ProjectionElem::OpaqueCast(_)
             | ProjectionElem::ConstantIndex { .. }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index b1a79a93826..5d8b1956afb 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -357,7 +357,9 @@ impl<'tcx> Validator<'_, 'tcx> {
                         return Err(Unpromotable);
                     }
 
-                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
+                    ProjectionElem::ConstantIndex { .. }
+                    | ProjectionElem::Subtype(_)
+                    | ProjectionElem::Subslice { .. } => {}
 
                     ProjectionElem::Index(local) => {
                         let mut promotable = false;
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 5289557c01b..ecedfc74450 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -608,6 +608,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
+        match operand {
+            Operand::Copy(place) | Operand::Move(place) => {
+                if let Some(stmt) = self.body.stmt_at(location).left() {
+                    match &stmt.kind {
+                        StatementKind::Assign(box (lval, rvalue)) => {
+                            let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
+                            let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty;
+
+                            if !place.is_subtype()
+                                && place_ty != lval_ty
+                                && rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty
+                                && (rvalue.ty(&self.body.local_decls, self.tcx).is_closure()
+                                    != lval_ty.is_closure())
+                            {
+                                self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}"))
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+            }
+            _ => (),
+        }
         // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
         if self.tcx.sess.opts.unstable_opts.validate_mir
             && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
@@ -1088,6 +1111,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 // LHS and RHS of the assignment must have the same type.
                 let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
                 let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
+
                 if !self.mir_assign_valid_types(right_ty, left_ty) {
                     self.fail(
                         location,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index e30172727f2..e405de90ee5 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1075,6 +1075,8 @@ pub enum ProjectionElem<V, T> {
     /// Like an explicit cast from an opaque type to a concrete type, but without
     /// requiring an intermediate variable.
     OpaqueCast(T),
+
+    Subtype(T),
 }
 
 /// Alias for projections as they appear in places, where the base is a place
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index bcbc5aa4744..c3c08276249 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -111,6 +111,7 @@ impl<'tcx> PlaceTy<'tcx> {
             }
             ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
             ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
+            ProjectionElem::Subtype(_) => PlaceTy::from_ty(self.ty),
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index ea447d1538c..5ea8325412b 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1110,6 +1110,7 @@ macro_rules! visit_place_fns {
                     if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
                 }
                 PlaceElem::Deref
+                | PlaceElem::Subtype { .. }
                 | PlaceElem::ConstantIndex { .. }
                 | PlaceElem::Subslice { .. }
                 | PlaceElem::Downcast(..) => None,
@@ -1175,7 +1176,9 @@ macro_rules! visit_place_fns {
             location: Location,
         ) {
             match elem {
-                ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
+                ProjectionElem::OpaqueCast(ty)
+                | ProjectionElem::Subtype(ty)
+                | ProjectionElem::Field(_, ty) => {
                     self.visit_ty(ty, TyContext::Location(location));
                 }
                 ProjectionElem::Index(local) => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 560c804e0b5..5bccba4fddd 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -102,7 +102,7 @@ fn convert_to_hir_projections_and_truncate_for_capture(
                 continue;
             }
             // These do not affect anything, they just make sure we know the right type.
-            ProjectionElem::OpaqueCast(_) => continue,
+            ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
             ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. } => {
@@ -709,6 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     ProjectionElem::Field(..)
                     | ProjectionElem::Downcast(..)
                     | ProjectionElem::OpaqueCast(..)
+                    | ProjectionElem::Subtype(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. } => (),
                 }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
index 7806e8f45d3..2a7f23ef6d2 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
@@ -57,6 +57,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
                 ProjectionElem::ConstantIndex { offset, min_length, from_end }
             }
             ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
+            ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty.lift()),
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 9ced3a7f3cd..0e4fc2447e1 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -112,6 +112,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
         let mut union_path = None;
 
         for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
+            if elem.is_subtype() {
+                continue;
+            }
             let body = self.builder.body;
             let tcx = self.builder.tcx;
             let place_ty = place_ref.ty(body, tcx).ty;
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
new file mode 100644
index 00000000000..e51f4a2ff21
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -0,0 +1,57 @@
+use crate::MirPass;
+use rustc_index::IndexVec;
+use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::MutVisitor;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+pub struct Subtyper;
+
+pub struct SubTypeCheker<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    patcher: MirPatch<'tcx>,
+    local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
+}
+
+impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_assign(
+        &mut self,
+        place: &mut Place<'tcx>,
+        rvalue: &mut Rvalue<'tcx>,
+        location: Location,
+    ) {
+        let place_ty = place.ty(self.local_decls, self.tcx);
+        let rval_ty = rvalue.ty(self.local_decls, self.tcx);
+        if place_ty.ty != rval_ty {
+            let temp = self
+                .patcher
+                .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
+            let new_place =
+                Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
+            self.patcher.add_assign(location, new_place, rvalue.clone());
+            let new_rval = Rvalue::Use(Operand::Move(new_place));
+            *rvalue = new_rval;
+        }
+    }
+}
+
+pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let patch = MirPatch::new(body);
+    let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls };
+
+    for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
+        checker.visit_basic_block_data(bb, data);
+    }
+
+    checker.patcher.apply(body);
+}
+
+impl<'tcx> MirPass<'tcx> for Subtyper {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        subtype_finder(tcx, body);
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 754f2ee8376..22381844d6d 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -54,6 +54,7 @@ mod check_packed_ref;
 pub mod check_unsafety;
 mod remove_place_mention;
 // This pass is public to allow external drivers to perform MIR cleanup
+mod add_subtyping_projections;
 pub mod cleanup_post_borrowck;
 mod const_debuginfo;
 mod const_goto;
@@ -466,6 +467,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
 /// After this series of passes, no lifetime analysis based on borrowing can be done.
 fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let passes: &[&dyn MirPass<'tcx>] = &[
+        &add_subtyping_projections::Subtyper,
         &cleanup_post_borrowck::CleanupPostBorrowck,
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::EarlyOpt,
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 17233058c9c..55f9cb27ad4 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -272,6 +272,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Deref
+            | ProjectionElem::Subtype(_)
             | ProjectionElem::Index(_) => {},
         }
     }
diff --git a/tests/mir-opt/mir_subtyping.main.Subtyper.diff b/tests/mir-opt/mir_subtyping.main.Subtyper.diff
new file mode 100644
index 00000000000..233915d48d7
--- /dev/null
+++ b/tests/mir-opt/mir_subtyping.main.Subtyper.diff
@@ -0,0 +1,262 @@
+- // MIR for `main` before Subtyper
++ // MIR for `main` after Subtyper
+  
+  | User Type Annotations
+  | 0: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:18, inferred_ty: fn(Foo<fn(&u8)>) -> std::boxed::Box<Foo<fn(&u8)>> {std::boxed::Box::<Foo<fn(&u8)>>::new}
+  | 1: user_ty: Canonical { value: Ty(fn(&'static u8)), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:34:23: 34:48, inferred_ty: fn(&u8)
+  | 2: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = std::string::String>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:87, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>
+  | 3: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:18, inferred_ty: fn(Foo<for<'a> fn(&'a u8)>) -> std::boxed::Box<Foo<for<'a> fn(&'a u8)>> {std::boxed::Box::<Foo<for<'a> fn(&'a u8)>>::new}
+  | 4: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:83, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>
+  | 5: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:37:20: 37:28, inferred_ty: fn(Foo<for<'a> fn(&'a u8)>) -> std::boxed::Box<Foo<for<'a> fn(&'a u8)>> {std::boxed::Box::<Foo<for<'a> fn(&'a u8)>>::new}
+  | 6: user_ty: Canonical { value: Ty(std::boxed::Box<Foo<fn(&'static u8)>>), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:38:20: 38:57, inferred_ty: std::boxed::Box<Foo<fn(&u8)>>
+  | 7: user_ty: Canonical { value: Ty(std::boxed::Box<dyn GetInner<Assoc = std::string::String>>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:39:19: 39:64, inferred_ty: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>
+  |
+  fn main() -> () {
+      let mut _0: ();
+      let _1: Wrapper;
+      let mut _2: for<'a> fn(&'a u8);
+      let _3: ();
+      let mut _4: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
+      let mut _5: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
+      let mut _6: std::boxed::Box<Foo<fn(&u8)>>;
+      let mut _7: Foo<fn(&u8)>;
+      let mut _8: fn(&u8);
+      let mut _9: fn(&u8);
+      let _10: ();
+      let mut _11: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>;
+      let mut _12: std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>>;
+      let mut _13: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
+      let mut _14: Foo<for<'a> fn(&'a u8)>;
+      let mut _15: for<'a> fn(&'a u8);
+      let mut _17: Foo<for<'a> fn(&'a u8)>;
+      let mut _18: for<'b> fn(&'b u8);
+      let mut _20: std::boxed::Box<Foo<fn(&u8)>>;
+      let mut _22: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
+      let mut _23: std::boxed::Box<Foo<fn(&u8)>>;
+      let mut _25: &mut dyn GetInner<Assoc = std::string::String>;
+      let _26: ();
+      let mut _27: std::string::String;
++     let mut _28: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
+      scope 1 {
+          debug wrapper => _1;
+          let _16: std::boxed::Box<Foo<for<'a> fn(&'a u8)>>;
+          scope 2 {
+              debug hr_fnptr => _16;
+              let _19: std::boxed::Box<Foo<fn(&u8)>>;
+              scope 3 {
+                  debug lr_fnptr => _19;
+                  let mut _21: std::boxed::Box<dyn GetInner<Assoc = std::string::String>>;
+                  scope 4 {
+                      debug any => _21;
+                      let _24: std::string::String;
+                      scope 5 {
+                          debug evil_string => _24;
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
+          _1 = Wrapper(move _2);
+          StorageDead(_2);
+          FakeRead(ForLet(None), _1);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
+          AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] });
+          _8 = _9;
+          _7 = Foo::<fn(&u8)>(move _8);
+          StorageDead(_8);
+          _6 = Box::<Foo<fn(&u8)>>::new(move _7) -> [return: bb1, unwind: bb28];
+      }
+  
+      bb1: {
+          _5 = move _6 as std::boxed::Box<dyn GetInner<Assoc = std::string::String>> (PointerCoercion(Unsize));
+          drop(_6) -> [return: bb2, unwind: bb28];
+      }
+  
+      bb2: {
+          StorageDead(_7);
+          StorageDead(_6);
+          AscribeUserType(_5, o, UserTypeProjection { base: UserType(2), projs: [] });
+          _4 = move _5;
+          _3 = std::mem::drop::<Box<dyn GetInner<Assoc = String>>>(move _4) -> [return: bb3, unwind: bb26];
+      }
+  
+      bb3: {
+          StorageDead(_4);
+          drop(_5) -> [return: bb4, unwind: bb28];
+      }
+  
+      bb4: {
+          StorageDead(_9);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageLive(_10);
+          StorageLive(_11);
+          StorageLive(_12);
+          StorageLive(_13);
+          StorageLive(_14);
+          StorageLive(_15);
+          _15 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer));
+          _14 = Foo::<for<'a> fn(&'a u8)>(move _15);
+          StorageDead(_15);
+          _13 = Box::<Foo<for<'a> fn(&'a u8)>>::new(move _14) -> [return: bb5, unwind: bb28];
+      }
+  
+      bb5: {
+          _12 = move _13 as std::boxed::Box<dyn GetInner<Assoc = [usize; 3]>> (PointerCoercion(Unsize));
+          drop(_13) -> [return: bb6, unwind: bb28];
+      }
+  
+      bb6: {
+          StorageDead(_14);
+          StorageDead(_13);
+          AscribeUserType(_12, o, UserTypeProjection { base: UserType(4), projs: [] });
+          _11 = move _12;
+          _10 = std::mem::drop::<Box<dyn GetInner<Assoc = [usize; 3]>>>(move _11) -> [return: bb7, unwind: bb24];
+      }
+  
+      bb7: {
+          StorageDead(_11);
+          drop(_12) -> [return: bb8, unwind: bb28];
+      }
+  
+      bb8: {
+          StorageDead(_12);
+          StorageDead(_10);
+          StorageLive(_16);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = (_1.0: for<'b> fn(&'b u8));
+          _17 = Foo::<for<'a> fn(&'a u8)>(move _18);
+          StorageDead(_18);
+          _16 = Box::<Foo<for<'a> fn(&'a u8)>>::new(move _17) -> [return: bb9, unwind: bb28];
+      }
+  
+      bb9: {
+          StorageDead(_17);
+          FakeRead(ForLet(None), _16);
+          StorageLive(_19);
+          StorageLive(_20);
+-         _20 = move _16;
++         _20 = move (_16 Subtyped as Box<Foo<fn(&u8)>>;
+          AscribeUserType(_20, o, UserTypeProjection { base: UserType(6), projs: [] });
+          _19 = move _20;
+          FakeRead(ForLet(None), _19);
+          drop(_20) -> [return: bb10, unwind: bb22];
+      }
+  
+      bb10: {
+          StorageDead(_20);
+          StorageLive(_21);
+          StorageLive(_22);
+          StorageLive(_23);
+          _23 = move _19;
+          _22 = move _23 as std::boxed::Box<dyn GetInner<Assoc = std::string::String>> (PointerCoercion(Unsize));
+          drop(_23) -> [return: bb11, unwind: bb22];
+      }
+  
+      bb11: {
+          StorageDead(_23);
+          AscribeUserType(_22, o, UserTypeProjection { base: UserType(7), projs: [] });
+          _21 = move _22;
+          FakeRead(ForLet(None), _21);
+          drop(_22) -> [return: bb12, unwind: bb21];
+      }
+  
+      bb12: {
+          StorageDead(_22);
+          StorageLive(_24);
+          StorageLive(_25);
+          _25 = &mut (*_21);
+          _24 = <dyn GetInner<Assoc = String> as GetInner>::muahaha(move _25) -> [return: bb13, unwind: bb21];
+      }
+  
+      bb13: {
+          StorageDead(_25);
+          FakeRead(ForLet(None), _24);
+          StorageLive(_26);
+          StorageLive(_27);
+          _27 = move _24;
+          _26 = std::mem::drop::<String>(move _27) -> [return: bb14, unwind: bb19];
+      }
+  
+      bb14: {
+          StorageDead(_27);
+          StorageDead(_26);
+          _0 = const ();
+          drop(_24) -> [return: bb15, unwind: bb21];
+      }
+  
+      bb15: {
+          StorageDead(_24);
+          drop(_21) -> [return: bb16, unwind: bb22];
+      }
+  
+      bb16: {
+          StorageDead(_21);
+          drop(_19) -> [return: bb17, unwind: bb23];
+      }
+  
+      bb17: {
+          StorageDead(_19);
+          drop(_16) -> [return: bb18, unwind: bb28];
+      }
+  
+      bb18: {
+          StorageDead(_16);
+          StorageDead(_1);
+          return;
+      }
+  
+      bb19 (cleanup): {
+          drop(_27) -> [return: bb20, unwind terminate];
+      }
+  
+      bb20 (cleanup): {
+          drop(_24) -> [return: bb21, unwind terminate];
+      }
+  
+      bb21 (cleanup): {
+          drop(_21) -> [return: bb22, unwind terminate];
+      }
+  
+      bb22 (cleanup): {
+          drop(_19) -> [return: bb23, unwind terminate];
+      }
+  
+      bb23 (cleanup): {
+          drop(_16) -> [return: bb28, unwind terminate];
+      }
+  
+      bb24 (cleanup): {
+          drop(_11) -> [return: bb25, unwind terminate];
+      }
+  
+      bb25 (cleanup): {
+          drop(_12) -> [return: bb28, unwind terminate];
+      }
+  
+      bb26 (cleanup): {
+          drop(_4) -> [return: bb27, unwind terminate];
+      }
+  
+      bb27 (cleanup): {
+          drop(_5) -> [return: bb28, unwind terminate];
+      }
+  
+      bb28 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/mir_subtyping.rs b/tests/mir-opt/mir_subtyping.rs
new file mode 100644
index 00000000000..558ccaca9f3
--- /dev/null
+++ b/tests/mir-opt/mir_subtyping.rs
@@ -0,0 +1,43 @@
+// compile-flags: -Z mir-opt-level=0
+
+// EMIT_MIR mir_subtyping.main.Subtyper.diff
+#![allow(coherence_leak_check)]
+
+struct Foo<T: 'static>(T);
+
+fn useful<'a>(_: &'a u8) {}
+
+pub struct Wrapper(for<'b> fn(&'b u8));
+
+trait GetInner {
+    type Assoc;
+    fn muahaha(&mut self) -> Self::Assoc;
+}
+
+impl GetInner for Foo<fn(&'static u8)> {
+    type Assoc = String;
+    fn muahaha(&mut self) -> String {
+        panic!("cant do it boss")
+    }
+}
+
+impl GetInner for Foo<for<'a> fn(&'a u8)> {
+    type Assoc = [usize; 3];
+    fn muahaha(&mut self) -> [usize; 3] {
+        [100; 3]
+    }
+}
+
+fn main() {
+    let wrapper = Wrapper(useful);
+
+    drop(Box::new(Foo(useful as fn(&'static u8))) as Box<dyn GetInner<Assoc = String>>);
+    drop(Box::new(Foo(useful as fn(&u8))) as Box<dyn GetInner<Assoc = [usize; 3]>>);
+
+    let hr_fnptr = Box::new(Foo::<for<'a> fn(&'a u8)>(wrapper.0));
+    let lr_fnptr = hr_fnptr as Box<Foo<fn(&'static u8)>>;
+    let mut any = lr_fnptr as Box<dyn GetInner<Assoc = String>>;
+
+    let evil_string = any.muahaha();
+    drop(evil_string);
+}
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
index ec894fa511a..67afa50bd58 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir
@@ -22,6 +22,7 @@ fn main() -> () {
     let _24: i32;
     let mut _26: *const i32;
     let _27: ();
+    let mut _29: [closure@main::{closure#0}];
     scope 1 {
         debug x => _1;
         let _3: &mut i32;
@@ -105,7 +106,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
index d89124f699b..467b4493bf3 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
@@ -22,6 +22,7 @@ fn main() -> () {
     let _24: i32;
     let mut _26: *const i32;
     let _27: ();
+    let mut _29: [closure@main::{closure#0}];
     scope 1 {
         debug x => _1;
         let _3: &mut i32;
@@ -105,7 +106,7 @@ fn main() -> () {
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);