have better explanation for relate_types
This commit is contained in:
parent
6f0c5ee2d4
commit
5d753abb30
@ -716,11 +716,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
PlaceTy::from_ty(fty)
|
PlaceTy::from_ty(fty)
|
||||||
}
|
}
|
||||||
ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message(
|
ProjectionElem::Subtype(_) => {
|
||||||
tcx,
|
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
|
||||||
self.last_span,
|
}
|
||||||
"ProjectionElem::Subtype shouldn't exist in borrowck",
|
|
||||||
)),
|
|
||||||
ProjectionElem::OpaqueCast(ty) => {
|
ProjectionElem::OpaqueCast(ty) => {
|
||||||
let ty = self.sanitize_type(place, ty);
|
let ty = self.sanitize_type(place, ty);
|
||||||
let ty = self.cx.normalize(ty, location);
|
let ty = self.cx.normalize(ty, location);
|
||||||
|
@ -674,7 +674,7 @@ impl<'tcx> CPlace<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used for `ProjectionElem::Subtype`, ty has to be monomorphized before
|
/// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before
|
||||||
/// passed on.
|
/// passed on.
|
||||||
pub(crate) fn place_transmute_type(
|
pub(crate) fn place_transmute_type(
|
||||||
self,
|
self,
|
||||||
|
@ -30,9 +30,9 @@ pub fn is_equal_up_to_subtyping<'tcx>(
|
|||||||
|
|
||||||
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
|
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
|
||||||
///
|
///
|
||||||
/// For almost all of the use cases variance should be `Covariant`,
|
/// When validating assignments, the variance should be `Covariant`. When checking
|
||||||
/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should
|
/// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant`
|
||||||
/// be `Invariant`.
|
/// because we want to check for type equality.
|
||||||
///
|
///
|
||||||
/// This mostly ignores opaque types as it can be used in constraining contexts
|
/// This mostly ignores opaque types as it can be used in constraining contexts
|
||||||
/// while still computing the final underlying type.
|
/// while still computing the final underlying type.
|
||||||
|
@ -1127,7 +1127,7 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
|
|||||||
write!(fmt, " as {ty})")?;
|
write!(fmt, " as {ty})")?;
|
||||||
}
|
}
|
||||||
ProjectionElem::Subtype(ty) => {
|
ProjectionElem::Subtype(ty) => {
|
||||||
write!(fmt, "as {ty})")?;
|
write!(fmt, " as subtype {ty})")?;
|
||||||
}
|
}
|
||||||
ProjectionElem::Downcast(Some(name), _index) => {
|
ProjectionElem::Downcast(Some(name), _index) => {
|
||||||
write!(fmt, " as {name})")?;
|
write!(fmt, " as {name})")?;
|
||||||
|
@ -1077,9 +1077,12 @@ pub enum ProjectionElem<V, T> {
|
|||||||
OpaqueCast(T),
|
OpaqueCast(T),
|
||||||
|
|
||||||
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
|
/// 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
|
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
|
||||||
/// explicit during optimizations and codegen.
|
/// explicit during optimizations and codegen.
|
||||||
///
|
///
|
||||||
|
/// This projection doesn't impact the runtime behavior of the program except for potentially changing
|
||||||
|
/// some type metadata of the interpreter or codegen backend.
|
||||||
|
///
|
||||||
/// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
|
/// 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
|
/// borrowchecker, as we only care about subtyping that can affect trait selection and
|
||||||
/// `TypeId`.
|
/// `TypeId`.
|
||||||
|
@ -69,7 +69,7 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
elem: &ProjectionElem<V, T>,
|
elem: &ProjectionElem<V, T>,
|
||||||
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
|
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
|
||||||
mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
|
mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
|
||||||
) -> PlaceTy<'tcx>
|
) -> PlaceTy<'tcx>
|
||||||
where
|
where
|
||||||
V: ::std::fmt::Debug,
|
V: ::std::fmt::Debug,
|
||||||
@ -110,8 +110,12 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||||||
PlaceTy { ty: self.ty, variant_index: Some(index) }
|
PlaceTy { ty: self.ty, variant_index: Some(index) }
|
||||||
}
|
}
|
||||||
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
|
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
|
||||||
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
|
ProjectionElem::OpaqueCast(ty) => {
|
||||||
ProjectionElem::Subtype(_) => PlaceTy::from_ty(self.ty),
|
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
|
||||||
|
}
|
||||||
|
ProjectionElem::Subtype(ty) => {
|
||||||
|
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
|
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
|
||||||
answer
|
answer
|
||||||
|
@ -112,8 +112,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||||||
let mut union_path = None;
|
let mut union_path = None;
|
||||||
|
|
||||||
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
|
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
|
||||||
// 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 body = self.builder.body;
|
||||||
let tcx = self.builder.tcx;
|
let tcx = self.builder.tcx;
|
||||||
let place_ty = place_ref.ty(body, tcx).ty;
|
let place_ty = place_ref.ty(body, tcx).ty;
|
||||||
@ -229,8 +227,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
_ => bug!("Unexpected type {place_ty:#?}"),
|
_ => bug!("Unexpected type {place_ty:#?}"),
|
||||||
},
|
},
|
||||||
// `OpaqueCast` only transmutes the type, so no moves there and
|
// `OpaqueCast`:Only transmutes the type, so no moves there.
|
||||||
// `Downcast` only changes information about a `Place` without moving
|
// `Downcast` :Only changes information about a `Place` without moving.
|
||||||
|
// `Subtype` :Only transmutes the type, so moves.
|
||||||
// So it's safe to skip these.
|
// So it's safe to skip these.
|
||||||
ProjectionElem::OpaqueCast(_)
|
ProjectionElem::OpaqueCast(_)
|
||||||
| ProjectionElem::Subtype(_)
|
| ProjectionElem::Subtype(_)
|
||||||
|
@ -24,24 +24,31 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
|
|||||||
rvalue: &mut Rvalue<'tcx>,
|
rvalue: &mut Rvalue<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
let place_ty = place.ty(self.local_decls, self.tcx);
|
let mut place_ty = place.ty(self.local_decls, self.tcx).ty;
|
||||||
let mut 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,
|
||||||
// Not erasing this causes `Free Regions` errors in validator,
|
// when rval is `ReStatic`.
|
||||||
// when rval is `ReStatic`.
|
rval_ty = self.tcx.erase_regions_ty(rval_ty);
|
||||||
rval_ty = self.tcx.erase_regions_ty(rval_ty);
|
place_ty = self.tcx.erase_regions(place_ty);
|
||||||
|
if place_ty != rval_ty {
|
||||||
let temp = self
|
let temp = self
|
||||||
.patcher
|
.patcher
|
||||||
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
|
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
|
||||||
let new_place = Place::from(temp);
|
let new_place = Place::from(temp);
|
||||||
self.patcher.add_assign(location, new_place, rvalue.clone());
|
self.patcher.add_assign(location, new_place, rvalue.clone());
|
||||||
let subtyped =
|
let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx);
|
||||||
new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
|
|
||||||
*rvalue = Rvalue::Use(Operand::Move(subtyped));
|
*rvalue = Rvalue::Use(Operand::Move(subtyped));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aim here is to do this kind of transformation:
|
||||||
|
//
|
||||||
|
// let place: place_ty = rval;
|
||||||
|
// // gets transformed to
|
||||||
|
// let temp: rval_ty = rval;
|
||||||
|
// let place: place_ty = temp as place_ty;
|
||||||
|
//
|
||||||
pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let patch = MirPatch::new(body);
|
let patch = MirPatch::new(body);
|
||||||
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
|
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 9434648ba82a0519222677bcc3fdf8b4f1ac5ced
|
|
@ -37,7 +37,7 @@
|
|||||||
- _4 = g() -> [return: bb1, unwind unreachable];
|
- _4 = g() -> [return: bb1, unwind unreachable];
|
||||||
+ StorageLive(_5);
|
+ StorageLive(_5);
|
||||||
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||||
+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
+ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||||
+ StorageDead(_5);
|
+ StorageDead(_5);
|
||||||
+ _3 = &mut _4;
|
+ _3 = &mut _4;
|
||||||
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
|
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
- bb1: {
|
- bb1: {
|
||||||
+ StorageLive(_5);
|
+ StorageLive(_5);
|
||||||
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)};
|
||||||
+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
+ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8});
|
||||||
+ StorageDead(_5);
|
+ StorageDead(_5);
|
||||||
_3 = &mut _4;
|
_3 = &mut _4;
|
||||||
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5];
|
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5];
|
||||||
|
@ -22,7 +22,6 @@ fn main() -> () {
|
|||||||
let _24: i32;
|
let _24: i32;
|
||||||
let mut _26: *const i32;
|
let mut _26: *const i32;
|
||||||
let _27: ();
|
let _27: ();
|
||||||
let mut _29: for<'a> fn(&'a i32) -> &'a i32;
|
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
let _3: &mut i32;
|
let _3: &mut i32;
|
||||||
@ -106,8 +105,7 @@ fn main() -> () {
|
|||||||
StorageLive(_14);
|
StorageLive(_14);
|
||||||
_14 = {closure@main::{closure#0}};
|
_14 = {closure@main::{closure#0}};
|
||||||
Retag(_14);
|
Retag(_14);
|
||||||
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
_13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
||||||
_13 = move (_29as for<'a> fn(&'a i32) -> &'a i32);
|
|
||||||
StorageDead(_14);
|
StorageDead(_14);
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
@ -22,7 +22,6 @@ fn main() -> () {
|
|||||||
let _24: i32;
|
let _24: i32;
|
||||||
let mut _26: *const i32;
|
let mut _26: *const i32;
|
||||||
let _27: ();
|
let _27: ();
|
||||||
let mut _29: for<'a> fn(&'a i32) -> &'a i32;
|
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
let _3: &mut i32;
|
let _3: &mut i32;
|
||||||
@ -106,8 +105,7 @@ fn main() -> () {
|
|||||||
StorageLive(_14);
|
StorageLive(_14);
|
||||||
_14 = {closure@main::{closure#0}};
|
_14 = {closure@main::{closure#0}};
|
||||||
Retag(_14);
|
Retag(_14);
|
||||||
_29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
_13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
|
||||||
_13 = move (_29as for<'a> fn(&'a i32) -> &'a i32);
|
|
||||||
StorageDead(_14);
|
StorageDead(_14);
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user