have better explanation for relate_types

This commit is contained in:
ouz-a 2023-10-02 11:22:48 +03:00
parent 6f0c5ee2d4
commit 5d753abb30
13 changed files with 40 additions and 34 deletions

View File

@ -716,11 +716,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message(
tcx,
self.last_span,
"ProjectionElem::Subtype shouldn't exist in borrowck",
)),
ProjectionElem::Subtype(_) => {
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
}
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);

View File

@ -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.
pub(crate) fn place_transmute_type(
self,

View File

@ -30,9 +30,9 @@ pub fn is_equal_up_to_subtyping<'tcx>(
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
///
/// For almost all of the use cases variance should be `Covariant`,
/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should
/// be `Invariant`.
/// When validating assignments, the variance should be `Covariant`. When checking
/// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant`
/// because we want to check for type equality.
///
/// This mostly ignores opaque types as it can be used in constraining contexts
/// while still computing the final underlying type.

View File

@ -1127,7 +1127,7 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
write!(fmt, " as {ty})")?;
}
ProjectionElem::Subtype(ty) => {
write!(fmt, "as {ty})")?;
write!(fmt, " as subtype {ty})")?;
}
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {name})")?;

View File

@ -1077,9 +1077,12 @@ pub enum ProjectionElem<V, T> {
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
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
/// 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
/// borrowchecker, as we only care about subtyping that can affect trait selection and
/// `TypeId`.

View File

@ -69,7 +69,7 @@ impl<'tcx> PlaceTy<'tcx> {
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
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>
where
V: ::std::fmt::Debug,
@ -110,8 +110,12 @@ impl<'tcx> PlaceTy<'tcx> {
PlaceTy { ty: self.ty, variant_index: Some(index) }
}
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),
ProjectionElem::OpaqueCast(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);
answer

View File

@ -112,8 +112,6 @@ 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()) {
// 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;
@ -229,8 +227,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
_ => bug!("Unexpected type {place_ty:#?}"),
},
// `OpaqueCast` only transmutes the type, so no moves there and
// `Downcast` only changes information about a `Place` without moving
// `OpaqueCast`:Only transmutes the type, so no moves there.
// `Downcast` :Only changes information about a `Place` without moving.
// `Subtype` :Only transmutes the type, so moves.
// So it's safe to skip these.
ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_)

View File

@ -24,24 +24,31 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
rvalue: &mut Rvalue<'tcx>,
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);
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);
// Not erasing this causes `Free Regions` errors in validator,
// when rval is `ReStatic`.
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
.patcher
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
let new_place = Place::from(temp);
self.patcher.add_assign(location, new_place, rvalue.clone());
let subtyped =
new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx);
*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>) {
let patch = MirPatch::new(body);
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };

@ -1 +0,0 @@
Subproject commit 9434648ba82a0519222677bcc3fdf8b4f1ac5ced

View File

@ -37,7 +37,7 @@
- _4 = g() -> [return: bb1, unwind unreachable];
+ StorageLive(_5);
+ _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);
+ _3 = &mut _4;
+ _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 };

View File

@ -40,7 +40,7 @@
- bb1: {
+ StorageLive(_5);
+ _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);
_3 = &mut _4;
- _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5];

View File

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

View File

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