Skip to content

Commit 3148e6a

Browse files
committed
subtyping_projections
1 parent 1770912 commit 3148e6a

File tree

28 files changed

+431
-5
lines changed

28 files changed

+431
-5
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2828,6 +2828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
28282828
}
28292829
ProjectionElem::ConstantIndex { .. }
28302830
| ProjectionElem::Subslice { .. }
2831+
| ProjectionElem::Subtype(_)
28312832
| ProjectionElem::Index(_) => kind,
28322833
},
28332834
place_ty.projection_ty(tcx, elem),

compiler/rustc_borrowck/src/diagnostics/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
242242
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
243243
ProjectionElem::Downcast(..) => (),
244244
ProjectionElem::OpaqueCast(..) => (),
245+
ProjectionElem::Subtype(..) => (),
245246
ProjectionElem::Field(field, _ty) => {
246247
// FIXME(project-rfc_2229#36): print capture precisely here.
247248
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -317,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
317318
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
318319
ProjectionElem::Deref
319320
| ProjectionElem::Index(..)
321+
| ProjectionElem::Subtype(..)
320322
| ProjectionElem::ConstantIndex { .. }
321323
| ProjectionElem::Subslice { .. } => {
322324
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
159159
[
160160
..,
161161
ProjectionElem::Index(_)
162+
| ProjectionElem::Subtype(_)
162163
| ProjectionElem::ConstantIndex { .. }
163164
| ProjectionElem::OpaqueCast { .. }
164165
| ProjectionElem::Subslice { .. }

compiler/rustc_borrowck/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
18031803
for (place_base, elem) in place.iter_projections().rev() {
18041804
match elem {
18051805
ProjectionElem::Index(_/*operand*/) |
1806+
ProjectionElem::Subtype(_) |
18061807
ProjectionElem::OpaqueCast(_) |
18071808
ProjectionElem::ConstantIndex { .. } |
18081809
// assigning to P[i] requires P to be valid.
@@ -2191,6 +2192,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21912192
| ProjectionElem::Index(..)
21922193
| ProjectionElem::ConstantIndex { .. }
21932194
| ProjectionElem::Subslice { .. }
2195+
| ProjectionElem::Subtype(..)
21942196
| ProjectionElem::OpaqueCast { .. }
21952197
| ProjectionElem::Downcast(..) => {
21962198
let upvar_field_projection = self.is_upvar_field_projection(place);

compiler/rustc_borrowck/src/places_conflict.rs

+3
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ fn place_components_conflict<'tcx>(
243243
}
244244

245245
(ProjectionElem::Deref, _, Deep)
246+
| (ProjectionElem::Subtype(_), _, _)
246247
| (ProjectionElem::Deref, _, AccessDepth::Drop)
247248
| (ProjectionElem::Field { .. }, _, _)
248249
| (ProjectionElem::Index { .. }, _, _)
@@ -359,6 +360,7 @@ fn place_projection_conflict<'tcx>(
359360
(
360361
ProjectionElem::Index(..),
361362
ProjectionElem::Index(..)
363+
| ProjectionElem::Subtype(..)
362364
| ProjectionElem::ConstantIndex { .. }
363365
| ProjectionElem::Subslice { .. },
364366
)
@@ -503,6 +505,7 @@ fn place_projection_conflict<'tcx>(
503505
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
504506
Overlap::EqualOrDisjoint
505507
}
508+
(ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint,
506509
(
507510
ProjectionElem::Deref
508511
| ProjectionElem::Field(..)

compiler/rustc_borrowck/src/prefixes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
8989
cursor = cursor_base;
9090
continue 'cursor;
9191
}
92+
ProjectionElem::Subtype(..) => continue 'cursor,
9293
ProjectionElem::Deref => {
9394
// (handled below)
9495
}

compiler/rustc_borrowck/src/type_check/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
621621
span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
622622
}))
623623
}
624+
ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty),
624625
ProjectionElem::Index(i) => {
625626
let index_ty = Place::from(i).ty(self.body(), tcx).ty;
626627
if index_ty != tcx.types.usize {
@@ -2556,6 +2557,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
25562557
}
25572558
}
25582559
ProjectionElem::Field(..)
2560+
| ProjectionElem::Subtype(..)
25592561
| ProjectionElem::Downcast(..)
25602562
| ProjectionElem::OpaqueCast(..)
25612563
| ProjectionElem::Index(..)

compiler/rustc_codegen_cranelift/src/base.rs

+3
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,9 @@ pub(crate) fn codegen_place<'tcx>(
872872

873873
for elem in place.projection {
874874
match elem {
875+
PlaceElem::Subtype(_) => {
876+
continue;
877+
}
875878
PlaceElem::Deref => {
876879
cplace = cplace.place_deref(fx);
877880
}

compiler/rustc_codegen_ssa/src/mir/place.rs

+1
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
499499
subslice
500500
}
501501
mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
502+
mir::ProjectionElem::Subtype(_) => continue,
502503
};
503504
}
504505
debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);

compiler/rustc_const_eval/src/interpret/operand.rs

+3
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
665665
let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?;
666666
// Using `try_fold` turned out to be bad for performance, hence the loop.
667667
for elem in mir_place.projection.iter() {
668+
if elem.is_subtype() {
669+
continue;
670+
}
668671
op = self.project(&op, elem)?
669672
}
670673

compiler/rustc_const_eval/src/interpret/projection.rs

+1
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ where
332332
self.project_constant_index(base, offset, min_length, from_end)?
333333
}
334334
Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?,
335+
Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?,
335336
})
336337
}
337338
}

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+1
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
664664
| ProjectionElem::Downcast(..)
665665
| ProjectionElem::OpaqueCast(..)
666666
| ProjectionElem::Subslice { .. }
667+
| ProjectionElem::Subtype(..)
667668
| ProjectionElem::Field(..)
668669
| ProjectionElem::Index(_) => {}
669670
}

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ where
306306
ProjectionElem::Index(index) if in_local(index) => return true,
307307

308308
ProjectionElem::Deref
309+
| ProjectionElem::Subtype(_)
309310
| ProjectionElem::Field(_, _)
310311
| ProjectionElem::OpaqueCast(_)
311312
| ProjectionElem::ConstantIndex { .. }

compiler/rustc_const_eval/src/transform/promote_consts.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,9 @@ impl<'tcx> Validator<'_, 'tcx> {
357357
return Err(Unpromotable);
358358
}
359359

360-
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
360+
ProjectionElem::ConstantIndex { .. }
361+
| ProjectionElem::Subtype(_)
362+
| ProjectionElem::Subslice { .. } => {}
361363

362364
ProjectionElem::Index(local) => {
363365
let mut promotable = false;

compiler/rustc_const_eval/src/transform/validate.rs

+24
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
608608

609609
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
610610
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
611+
match operand {
612+
Operand::Copy(place) | Operand::Move(place) => {
613+
if let Some(stmt) = self.body.stmt_at(location).left() {
614+
match &stmt.kind {
615+
StatementKind::Assign(box (lval, rvalue)) => {
616+
let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
617+
let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty;
618+
619+
if !place.is_subtype()
620+
&& place_ty != lval_ty
621+
&& rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty
622+
&& (rvalue.ty(&self.body.local_decls, self.tcx).is_closure()
623+
!= lval_ty.is_closure())
624+
{
625+
self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}"))
626+
}
627+
}
628+
_ => (),
629+
}
630+
}
631+
}
632+
_ => (),
633+
}
611634
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
612635
if self.tcx.sess.opts.unstable_opts.validate_mir
613636
&& self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
@@ -1088,6 +1111,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
10881111
// LHS and RHS of the assignment must have the same type.
10891112
let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
10901113
let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
1114+
10911115
if !self.mir_assign_valid_types(right_ty, left_ty) {
10921116
self.fail(
10931117
location,

compiler/rustc_middle/src/mir/syntax.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,8 @@ pub enum ProjectionElem<V, T> {
10751075
/// Like an explicit cast from an opaque type to a concrete type, but without
10761076
/// requiring an intermediate variable.
10771077
OpaqueCast(T),
1078+
1079+
Subtype(T),
10781080
}
10791081

10801082
/// Alias for projections as they appear in places, where the base is a place

compiler/rustc_middle/src/mir/tcx.rs

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ impl<'tcx> PlaceTy<'tcx> {
111111
}
112112
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
113113
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
114+
ProjectionElem::Subtype(_) => PlaceTy::from_ty(self.ty),
114115
};
115116
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
116117
answer

compiler/rustc_middle/src/mir/visit.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,7 @@ macro_rules! visit_place_fns {
11101110
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
11111111
}
11121112
PlaceElem::Deref
1113+
| PlaceElem::Subtype { .. }
11131114
| PlaceElem::ConstantIndex { .. }
11141115
| PlaceElem::Subslice { .. }
11151116
| PlaceElem::Downcast(..) => None,
@@ -1175,7 +1176,9 @@ macro_rules! visit_place_fns {
11751176
location: Location,
11761177
) {
11771178
match elem {
1178-
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
1179+
ProjectionElem::OpaqueCast(ty)
1180+
| ProjectionElem::Subtype(ty)
1181+
| ProjectionElem::Field(_, ty) => {
11791182
self.visit_ty(ty, TyContext::Location(location));
11801183
}
11811184
ProjectionElem::Index(local) => {

compiler/rustc_mir_build/src/build/expr/as_place.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fn convert_to_hir_projections_and_truncate_for_capture(
102102
continue;
103103
}
104104
// These do not affect anything, they just make sure we know the right type.
105-
ProjectionElem::OpaqueCast(_) => continue,
105+
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
106106
ProjectionElem::Index(..)
107107
| ProjectionElem::ConstantIndex { .. }
108108
| ProjectionElem::Subslice { .. } => {
@@ -709,6 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
709709
ProjectionElem::Field(..)
710710
| ProjectionElem::Downcast(..)
711711
| ProjectionElem::OpaqueCast(..)
712+
| ProjectionElem::Subtype(..)
712713
| ProjectionElem::ConstantIndex { .. }
713714
| ProjectionElem::Subslice { .. } => (),
714715
}

compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
5757
ProjectionElem::ConstantIndex { offset, min_length, from_end }
5858
}
5959
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
60+
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty.lift()),
6061
}
6162
}
6263
}

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
112112
let mut union_path = None;
113113

114114
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
115+
if elem.is_subtype() {
116+
continue;
117+
}
115118
let body = self.builder.body;
116119
let tcx = self.builder.tcx;
117120
let place_ty = place_ref.ty(body, tcx).ty;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use crate::MirPass;
2+
use rustc_index::IndexVec;
3+
use rustc_middle::mir::patch::MirPatch;
4+
use rustc_middle::mir::visit::MutVisitor;
5+
use rustc_middle::mir::*;
6+
use rustc_middle::ty::TyCtxt;
7+
8+
pub struct Subtyper;
9+
10+
pub struct SubTypeCheker<'a, 'tcx> {
11+
tcx: TyCtxt<'tcx>,
12+
patcher: MirPatch<'tcx>,
13+
local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
14+
}
15+
16+
impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
17+
fn tcx(&self) -> TyCtxt<'tcx> {
18+
self.tcx
19+
}
20+
21+
fn visit_assign(
22+
&mut self,
23+
place: &mut Place<'tcx>,
24+
rvalue: &mut Rvalue<'tcx>,
25+
location: Location,
26+
) {
27+
let place_ty = place.ty(self.local_decls, self.tcx);
28+
let rval_ty = rvalue.ty(self.local_decls, self.tcx);
29+
if place_ty.ty != rval_ty {
30+
let temp = self
31+
.patcher
32+
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
33+
let new_place =
34+
Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
35+
self.patcher.add_assign(location, new_place, rvalue.clone());
36+
let new_rval = Rvalue::Use(Operand::Move(new_place));
37+
*rvalue = new_rval;
38+
}
39+
}
40+
}
41+
42+
pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
43+
let patch = MirPatch::new(body);
44+
let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls };
45+
46+
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
47+
checker.visit_basic_block_data(bb, data);
48+
}
49+
50+
checker.patcher.apply(body);
51+
}
52+
53+
impl<'tcx> MirPass<'tcx> for Subtyper {
54+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
55+
subtype_finder(tcx, body);
56+
}
57+
}

compiler/rustc_mir_transform/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ mod check_packed_ref;
5454
pub mod check_unsafety;
5555
mod remove_place_mention;
5656
// This pass is public to allow external drivers to perform MIR cleanup
57+
mod add_subtyping_projections;
5758
pub mod cleanup_post_borrowck;
5859
mod const_debuginfo;
5960
mod const_goto;
@@ -466,6 +467,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
466467
/// After this series of passes, no lifetime analysis based on borrowing can be done.
467468
fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
468469
let passes: &[&dyn MirPass<'tcx>] = &[
470+
&add_subtyping_projections::Subtyper,
469471
&cleanup_post_borrowck::CleanupPostBorrowck,
470472
&remove_noop_landing_pads::RemoveNoopLandingPads,
471473
&simplify::SimplifyCfg::EarlyOpt,

src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs

+1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
272272
| ProjectionElem::Downcast(..)
273273
| ProjectionElem::Subslice { .. }
274274
| ProjectionElem::Deref
275+
| ProjectionElem::Subtype(_)
275276
| ProjectionElem::Index(_) => {},
276277
}
277278
}

0 commit comments

Comments
 (0)