Add docs, remove code, change subtyper code
This commit is contained in:
parent
3148e6a993
commit
cd7f471931
24 changed files with 106 additions and 363 deletions
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(..),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)?
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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})")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue