Add docs, remove code, change subtyper code

This commit is contained in:
ouz-a 2023-08-28 11:19:19 +03:00
parent 3148e6a993
commit cd7f471931
24 changed files with 106 additions and 363 deletions

View File

@ -318,13 +318,14 @@ 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)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
PlaceTy::from_ty(*ty)
}
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};

View File

@ -243,13 +243,13 @@ fn place_components_conflict<'tcx>(
}
(ProjectionElem::Deref, _, Deep)
| (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Deref, _, AccessDepth::Drop)
| (ProjectionElem::Field { .. }, _, _)
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
@ -360,7 +360,6 @@ fn place_projection_conflict<'tcx>(
(
ProjectionElem::Index(..),
ProjectionElem::Index(..)
| ProjectionElem::Subtype(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. },
)
@ -505,12 +504,12 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
Overlap::EqualOrDisjoint
}
(ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint,
(
ProjectionElem::Deref
| ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),

View File

@ -89,7 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
cursor = cursor_base;
continue 'cursor;
}
ProjectionElem::Subtype(..) => continue 'cursor,
ProjectionElem::Subtype(..) => {
panic!("Subtype projection is not allowed before borrow check")
}
ProjectionElem::Deref => {
// (handled below)
}

View File

@ -621,7 +621,6 @@ 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 {
@ -717,6 +716,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
ProjectionElem::Subtype(_) => {
let guard = span_mirbug_and_err!(
self,
place,
"ProjectionElem::Subtype shouldn't exist in borrowck"
);
PlaceTy::from_ty(Ty::new_error(tcx, guard))
}
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);

View File

@ -872,13 +872,11 @@ pub(crate) fn codegen_place<'tcx>(
for elem in place.projection {
match elem {
PlaceElem::Subtype(_) => {
continue;
}
PlaceElem::Deref => {
cplace = cplace.place_deref(fx);
}
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty),
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}

View File

@ -674,6 +674,14 @@ impl<'tcx> CPlace<'tcx> {
}
}
pub(crate) fn place_transmute_type(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
ty: Ty<'tcx>,
) -> CPlace<'tcx> {
CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) }
}
pub(crate) fn place_field(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,

View File

@ -466,6 +466,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::ProjectionElem::OpaqueCast(ty) => {
bug!("encountered OpaqueCast({ty}) in codegen")
}
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index);
@ -499,7 +500,6 @@ 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);

View File

@ -665,9 +665,6 @@ 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)?
}

View File

@ -319,6 +319,8 @@ where
OpaqueCast(ty) => {
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
}
// We don't want anything happening here, this is here as a dummy.
Subtype(_) => base.transmute(base.layout(), self)?,
Field(field, _) => self.project_field(base, field.index())?,
Downcast(_, variant) => self.project_downcast(base, variant)?,
Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
@ -332,7 +334,6 @@ 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)?,
})
}
}

View File

@ -16,6 +16,8 @@ use rustc_target::spec::abi::Abi;
use crate::util::is_within_packed;
use crate::util::is_subtype;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind {
Unwind,
@ -602,35 +604,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return true;
}
crate::util::is_subtype(self.tcx, self.param_env, src, dest)
return crate::util::is_subtype(self.tcx, self.param_env, src, dest);
}
}
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)
@ -776,6 +755,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
ProjectionElem::Subtype(ty) => {
if !is_subtype(
self.tcx,
self.param_env,
ty,
place_ref.ty(&self.body.local_decls, self.tcx).ty,
) {
self.fail(
location,
format!(
"Failed subtyping {ty:#?} and {:#?}",
place_ref.ty(&self.body.local_decls, self.tcx).ty
),
)
}
}
_ => {}
}
self.super_projection_elem(place_ref, elem, context, location);

View File

@ -1103,6 +1103,7 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
for &elem in projection.iter().rev() {
match elem {
ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _)
| ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
@ -1125,6 +1126,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
ProjectionElem::OpaqueCast(ty) => {
write!(fmt, " as {ty})")?;
}
ProjectionElem::Subtype(ty) => {
write!(fmt, "as {ty})")?;
}
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {name})")?;
}

View File

@ -57,6 +57,7 @@ impl<V, T> ProjectionElem<V, T> {
Self::Field(_, _)
| Self::Index(_)
| Self::OpaqueCast(_)
| Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => false,
@ -70,6 +71,7 @@ impl<V, T> ProjectionElem<V, T> {
Self::Deref | Self::Index(_) => false,
Self::Field(_, _)
| Self::OpaqueCast(_)
| Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => true,
@ -95,6 +97,7 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Field(_, _) => true,
Self::ConstantIndex { from_end: true, .. }
| Self::Index(_)
| Self::Subtype(_)
| Self::OpaqueCast(_)
| Self::Subslice { .. } => false,
}

View File

@ -1076,6 +1076,13 @@ pub enum ProjectionElem<V, T> {
/// requiring an intermediate variable.
OpaqueCast(T),
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
/// type of lvalue doesn't match type of rvalue, primary goal being making subtyping
/// explicit during optimizations and codegen.
///
/// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
/// borrowchecker, as we only care about subtyping that can affect trait selection and
/// `TypeId`.
Subtype(T),
}

View File

@ -1109,8 +1109,12 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
}
PlaceElem::Subtype(ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
}
PlaceElem::Deref
| PlaceElem::Subtype { .. }
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
| PlaceElem::Downcast(..) => None,

View File

@ -112,9 +112,8 @@ 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;
}
// We don't care creating `MovePath` for `ProjectionElem::Subtype(T)` because it's for debugging/validating
// purposes it's movement doesn't affect anything.
let body = self.builder.body;
let tcx = self.builder.tcx;
let place_ty = place_ref.ty(body, tcx).ty;
@ -233,7 +232,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// `OpaqueCast` only transmutes the type, so no moves there and
// `Downcast` only changes information about a `Place` without moving
// So it's safe to skip these.
ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (),
ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _) => (),
}
if union_path.is_none() {
// inlined from add_move_path because of a borrowck conflict with the iterator

View File

@ -7,13 +7,13 @@ use rustc_middle::ty::TyCtxt;
pub struct Subtyper;
pub struct SubTypeCheker<'a, 'tcx> {
pub struct SubTypeChecker<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
patcher: MirPatch<'tcx>,
local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
}
impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@ -25,28 +25,30 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
location: Location,
) {
let place_ty = place.ty(self.local_decls, self.tcx);
let rval_ty = rvalue.ty(self.local_decls, self.tcx);
let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
if place_ty.ty != rval_ty {
// Not erasing this causes `Free Regions` errors in validator,
// when rval is `ReStatic`.
rval_ty = self.tcx.erase_regions_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);
let new_place = Place::from(temp);
self.patcher.add_assign(location, new_place, rvalue.clone());
let new_rval = Rvalue::Use(Operand::Move(new_place));
*rvalue = new_rval;
let subtyped =
new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
*rvalue = Rvalue::Use(Operand::Move(subtyped));
}
}
}
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 };
let mut checker = SubTypeChecker { 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);
}

View File

@ -306,6 +306,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
};
value = self.insert(Value::Projection(value, proj));
}

14
tabula.rs Normal file
View File

@ -0,0 +1,14 @@
// run-pass
#![deny(drop_bounds)]
// As a special exemption, `impl Drop` in the return position raises no error.
// This allows a convenient way to return an unnamed drop guard.
fn voldemort_type() -> impl Drop {
struct Voldemort;
impl Drop for Voldemort {
fn drop(&mut self) {}
}
Voldemort
}
fn main() {
let _ = voldemort_type();
}

View File

@ -12,6 +12,7 @@
debug _r => _1;
}
+ scope 2 (inlined g) {
+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
+ }
+ scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
+ debug pointer => _3;

View File

@ -12,6 +12,7 @@
debug _r => _1;
}
+ scope 2 (inlined g) {
+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8];
+ }
+ scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) {
+ debug pointer => _3;
@ -55,7 +56,7 @@
- bb3: {
+ bb1: {
+ StorageDead(_5);
+ StorageDead(_6);
StorageDead(_2);
- drop(_4) -> [return: bb4, unwind: bb6];
+ drop(_4) -> [return: bb2, unwind: bb4];

View File

@ -1,262 +0,0 @@
- // 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;
}
}

View File

@ -1,43 +0,0 @@
// 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);
}

View File

@ -22,7 +22,7 @@ fn main() -> () {
let _24: i32;
let mut _26: *const i32;
let _27: ();
let mut _29: [closure@main::{closure#0}];
let mut _29: for<'a> fn(&'a i32) -> &'a i32;
scope 1 {
debug x => _1;
let _3: &mut i32;
@ -106,7 +106,8 @@ fn main() -> () {
StorageLive(_14);
_14 = {closure@main::{closure#0}};
Retag(_14);
_13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
_13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
StorageDead(_14);
StorageLive(_15);
StorageLive(_16);

View File

@ -22,7 +22,7 @@ fn main() -> () {
let _24: i32;
let mut _26: *const i32;
let _27: ();
let mut _29: [closure@main::{closure#0}];
let mut _29: for<'a> fn(&'a i32) -> &'a i32;
scope 1 {
debug x => _1;
let _3: &mut i32;
@ -106,7 +106,8 @@ fn main() -> () {
StorageLive(_14);
_14 = {closure@main::{closure#0}};
Retag(_14);
_13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
_13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32);
StorageDead(_14);
StorageLive(_15);
StorageLive(_16);