mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
subtyping_projections
This commit is contained in:
parent
177091258c
commit
3148e6a993
@ -2828,6 +2828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Index(_) => kind,
|
||||
},
|
||||
place_ty.projection_ty(tcx, elem),
|
||||
|
@ -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)
|
||||
|
@ -159,6 +159,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
[
|
||||
..,
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::OpaqueCast { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
|
@ -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);
|
||||
|
@ -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(..)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(..)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)?
|
||||
}
|
||||
|
||||
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -664,6 +664,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::OpaqueCast(..)
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Subtype(..)
|
||||
| ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(_) => {}
|
||||
}
|
||||
|
@ -306,6 +306,7 @@ where
|
||||
ProjectionElem::Index(index) if in_local(index) => return true,
|
||||
|
||||
ProjectionElem::Deref
|
||||
| ProjectionElem::Subtype(_)
|
||||
| ProjectionElem::Field(_, _)
|
||||
| ProjectionElem::OpaqueCast(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) => {
|
||||
|
@ -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 { .. } => (),
|
||||
}
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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(_) => {},
|
||||
}
|
||||
}
|
||||
|
262
tests/mir-opt/mir_subtyping.main.Subtyper.diff
Normal file
262
tests/mir-opt/mir_subtyping.main.Subtyper.diff
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
43
tests/mir-opt/mir_subtyping.rs
Normal file
43
tests/mir-opt/mir_subtyping.rs
Normal file
@ -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);
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user