Skip to content

Commit bf278eb

Browse files
committed
Make const index and subslice array projections more useful
* `min_length` is now exact for const index elements. * const index elements are always from the start. * make array `Subslice` `PlaceElems` count both `from` and `to` from the start.
1 parent 7de9402 commit bf278eb

File tree

11 files changed

+110
-54
lines changed

11 files changed

+110
-54
lines changed

Diff for: src/librustc/mir/mod.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -1714,18 +1714,25 @@ pub enum ProjectionElem<V, T> {
17141714
ConstantIndex {
17151715
/// index or -index (in Python terms), depending on from_end
17161716
offset: u32,
1717-
/// thing being indexed must be at least this long
1717+
/// The thing being indexed must be at least this long. For arrays this
1718+
/// is always the exact length.
17181719
min_length: u32,
1719-
/// counting backwards from end?
1720+
/// Counting backwards from end? This is always false when indexing an
1721+
/// array.
17201722
from_end: bool,
17211723
},
17221724

17231725
/// These indices are generated by slice patterns.
17241726
///
1725-
/// slice[from:-to] in Python terms.
1727+
/// If `from_end` is true `slice[from..slice.len() - to]`.
1728+
/// Otherwise `array[from..to]`.
17261729
Subslice {
17271730
from: u32,
17281731
to: u32,
1732+
/// Whether `to` counts from the start or end of the array/slice.
1733+
/// For `PlaceElem`s this is `true` if and only if the base is a slice.
1734+
/// For `ProjectionKind`, this can also be `true` for arrays.
1735+
from_end: bool,
17291736
},
17301737

17311738
/// "Downcast" to a variant of an ADT. Currently, we only introduce
@@ -1914,15 +1921,18 @@ impl Debug for Place<'_> {
19141921
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
19151922
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
19161923
}
1917-
ProjectionElem::Subslice { from, to } if *to == 0 => {
1924+
ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => {
19181925
write!(fmt, "[{:?}:]", from)?;
19191926
}
1920-
ProjectionElem::Subslice { from, to } if *from == 0 => {
1927+
ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => {
19211928
write!(fmt, "[:-{:?}]", to)?;
19221929
}
1923-
ProjectionElem::Subslice { from, to } => {
1930+
ProjectionElem::Subslice { from, to, from_end: true } => {
19241931
write!(fmt, "[{:?}:-{:?}]", from, to)?;
19251932
}
1933+
ProjectionElem::Subslice { from, to, from_end: false } => {
1934+
write!(fmt, "[{:?}..{:?}]", from, to)?;
1935+
}
19261936
}
19271937
}
19281938

@@ -2452,7 +2462,7 @@ impl UserTypeProjection {
24522462
}
24532463

24542464
pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
2455-
self.projs.push(ProjectionElem::Subslice { from, to });
2465+
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
24562466
self
24572467
}
24582468

Diff for: src/librustc/mir/tcx.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,17 @@ impl<'tcx> PlaceTy<'tcx> {
8888
}
8989
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
9090
PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
91-
ProjectionElem::Subslice { from, to } => {
91+
ProjectionElem::Subslice { from, to, from_end } => {
9292
PlaceTy::from_ty(match self.ty.kind {
93-
ty::Array(inner, size) => {
93+
ty::Slice(..) => self.ty,
94+
ty::Array(inner, _) if !from_end => {
95+
tcx.mk_array(inner, (to - from) as u64)
96+
}
97+
ty::Array(inner, size) if from_end => {
9498
let size = size.eval_usize(tcx, param_env);
9599
let len = size - (from as u64) - (to as u64);
96100
tcx.mk_array(inner, len)
97101
}
98-
ty::Slice(..) => self.ty,
99102
_ => {
100103
bug!("cannot subslice non-array type: `{:?}`", self)
101104
}

Diff for: src/librustc/mir/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ macro_rules! visit_place_fns {
954954
);
955955
}
956956
ProjectionElem::Deref |
957-
ProjectionElem::Subslice { from: _, to: _ } |
957+
ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
958958
ProjectionElem::ConstantIndex { offset: _,
959959
min_length: _,
960960
from_end: _ } |

Diff for: src/librustc_codegen_ssa/mir/place.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -565,14 +565,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
565565
let llindex = bx.sub(lllen, lloffset);
566566
cg_base.project_index(bx, llindex)
567567
}
568-
mir::ProjectionElem::Subslice { from, to } => {
568+
mir::ProjectionElem::Subslice { from, to, from_end } => {
569569
let mut subslice = cg_base.project_index(bx,
570570
bx.cx().const_usize(*from as u64));
571571
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
572572
.projection_ty(tcx, elem).ty;
573573
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
574574

575575
if subslice.layout.is_unsized() {
576+
assert!(from_end, "slice subslices should be `from_end`");
576577
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
577578
bx.cx().const_usize((*from as u64) + (*to as u64))));
578579
}

Diff for: src/librustc_mir/borrow_check/nll/type_check/mod.rs

+8-15
Original file line numberDiff line numberDiff line change
@@ -673,23 +673,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
673673
}),
674674
)
675675
}
676-
ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
676+
ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty(
677677
match base_ty.kind {
678-
ty::Array(inner, size) => {
679-
let size = size.eval_usize(tcx, self.cx.param_env);
680-
let min_size = (from as u64) + (to as u64);
681-
if let Some(rest_size) = size.checked_sub(min_size) {
682-
tcx.mk_array(inner, rest_size)
683-
} else {
684-
span_mirbug_and_err!(
685-
self,
686-
place,
687-
"taking too-small slice of {:?}",
688-
base_ty
689-
)
690-
}
678+
ty::Array(inner, _) => {
679+
assert!(!from_end, "array subslices should not use from_end");
680+
tcx.mk_array(inner, (to - from) as u64)
691681
}
692-
ty::Slice(..) => base_ty,
682+
ty::Slice(..) => {
683+
assert!(from_end, "slice subslices should use from_end");
684+
base_ty
685+
},
693686
_ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
694687
},
695688
),

Diff for: src/librustc_mir/borrow_check/places_conflict.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -503,34 +503,62 @@ fn place_projection_conflict<'tcx>(
503503
Overlap::Disjoint
504504
}
505505
}
506+
(
507+
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
508+
ProjectionElem::Subslice { from, to, from_end: false }
509+
)
510+
| (
511+
ProjectionElem::Subslice { from, to, from_end: false },
512+
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }
513+
) => {
514+
if (from..to).contains(&offset) {
515+
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
516+
Overlap::EqualOrDisjoint
517+
} else {
518+
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
519+
Overlap::Disjoint
520+
}
521+
}
506522
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
507523
ProjectionElem::Subslice {from, .. })
508524
| (ProjectionElem::Subslice {from, .. },
509525
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
510526
if offset >= from {
511527
debug!(
512-
"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
528+
"place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");
513529
Overlap::EqualOrDisjoint
514530
} else {
515-
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
531+
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
516532
Overlap::Disjoint
517533
}
518534
}
519535
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
520-
ProjectionElem::Subslice {from: _, to })
521-
| (ProjectionElem::Subslice {from: _, to },
536+
ProjectionElem::Subslice { to, .. })
537+
| (ProjectionElem::Subslice { to, .. },
522538
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
523539
if offset > to {
524540
debug!("place_element_conflict: \
525-
DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
541+
DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
526542
Overlap::EqualOrDisjoint
527543
} else {
528-
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
544+
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
545+
Overlap::Disjoint
546+
}
547+
}
548+
(
549+
ProjectionElem::Subslice { from: f1, to: t1, from_end: false },
550+
ProjectionElem::Subslice { from: f2, to: t2, from_end: false }
551+
) => {
552+
if f2 >= t1 || f1 >= t2 {
553+
debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");
529554
Overlap::Disjoint
555+
} else {
556+
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
557+
Overlap::EqualOrDisjoint
530558
}
531559
}
532560
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
533-
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
561+
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
534562
Overlap::EqualOrDisjoint
535563
}
536564
(ProjectionElem::Deref, _)

Diff for: src/librustc_mir/build/matches/util.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::build::Builder;
22
use crate::build::matches::MatchPair;
33
use crate::hair::*;
44
use rustc::mir::*;
5+
use rustc::ty;
56
use smallvec::SmallVec;
67
use std::u32;
78
use std::convert::TryInto;
@@ -31,9 +32,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3132
prefix: &'pat [Pat<'tcx>],
3233
opt_slice: Option<&'pat Pat<'tcx>>,
3334
suffix: &'pat [Pat<'tcx>]) {
34-
let min_length = prefix.len() + suffix.len();
35-
let min_length = min_length.try_into().unwrap();
3635
let tcx = self.hir.tcx();
36+
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
37+
ty::Array(_, length) => (
38+
length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(),
39+
true
40+
),
41+
_ => (
42+
(prefix.len() + suffix.len()).try_into().unwrap(),
43+
false,
44+
),
45+
};
3746

3847
match_pairs.extend(
3948
prefix.iter()
@@ -50,10 +59,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5059
);
5160

5261
if let Some(subslice_pat) = opt_slice {
53-
let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
54-
from: prefix.len() as u32,
55-
to: suffix.len() as u32
56-
});
62+
let suffix_len = suffix.len() as u32;
63+
let subslice = tcx.mk_place_elem(
64+
place.clone(),
65+
ProjectionElem::Subslice {
66+
from: prefix.len() as u32,
67+
to: if exact_size { min_length - suffix_len } else { suffix_len },
68+
from_end: !exact_size,
69+
},
70+
);
5771
match_pairs.push(MatchPair::new(subslice, subslice_pat));
5872
}
5973

@@ -62,10 +76,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6276
.rev()
6377
.enumerate()
6478
.map(|(idx, subpattern)| {
79+
let end_offset = (idx + 1) as u32;
6580
let elem = ProjectionElem::ConstantIndex {
66-
offset: (idx+1) as u32,
81+
offset: if exact_size { min_length - end_offset } else { end_offset },
6782
min_length,
68-
from_end: true,
83+
from_end: !exact_size,
6984
};
7085
let place = tcx.mk_place_elem(place.clone(), elem);
7186
MatchPair::new(place, subpattern)

Diff for: src/librustc_mir/dataflow/move_paths/abs_domain.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
4949
ProjectionElem::Deref => ProjectionElem::Deref,
5050
ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
5151
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
52-
ProjectionElem::Subslice { from, to } => {
53-
ProjectionElem::Subslice { from: from, to: to }
52+
ProjectionElem::Subslice { from, to, from_end } => {
53+
ProjectionElem::Subslice { from, to, from_end }
5454
}
5555
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
5656
ProjectionElem::ConstantIndex { offset, min_length, from_end }

Diff for: src/librustc_mir/dataflow/move_paths/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::slice::Iter;
22
use rustc::mir::*;
3-
use rustc::ty::{Ty, TyCtxt};
3+
use rustc::ty::{Ty, TyCtxt, ParamEnv};
44
use rustc::util::nodemap::FxHashMap;
55
use rustc_index::vec::{Enumerated, Idx, IndexVec};
66
use smallvec::SmallVec;
@@ -318,8 +318,9 @@ impl<'tcx> MoveData<'tcx> {
318318
pub fn gather_moves(
319319
body: &Body<'tcx>,
320320
tcx: TyCtxt<'tcx>,
321+
param_env: ParamEnv<'tcx>,
321322
) -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
322-
builder::gather_moves(body, tcx)
323+
builder::gather_moves(body, tcx, param_env)
323324
}
324325

325326
/// For the move path `mpi`, returns the root local variable (if any) that starts the path.

Diff for: src/librustc_mir/interpret/place.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,15 @@ where
451451
base: MPlaceTy<'tcx, M::PointerTag>,
452452
from: u64,
453453
to: u64,
454+
from_end: bool,
454455
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
455456
let len = base.len(self)?; // also asserts that we have a type where this makes sense
456-
assert!(from <= len - to);
457+
let actual_to = if from_end {
458+
assert!(from <= len - to);
459+
len - to
460+
} else {
461+
to
462+
};
457463

458464
// Not using layout method because that works with usize, and does not work with slices
459465
// (that have count 0 in their layout).
@@ -464,7 +470,7 @@ where
464470
};
465471

466472
// Compute meta and new layout
467-
let inner_len = len - to - from;
473+
let inner_len = actual_to - from;
468474
let (meta, ty) = match base.layout.ty.kind {
469475
// It is not nice to match on the type, but that seems to be the only way to
470476
// implement this.
@@ -528,8 +534,8 @@ where
528534
self.mplace_field(base, index)?
529535
}
530536

531-
Subslice { from, to } =>
532-
self.mplace_subslice(base, u64::from(from), u64::from(to))?,
537+
Subslice { from, to, from_end } =>
538+
self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?,
533539
})
534540
}
535541

Diff for: src/librustc_mir/transform/elaborate_drops.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
234234

235235
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
236236
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
237-
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
237+
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
238+
debug_assert!(size == *min_length, "min_length should be exact for arrays");
239+
assert!(!from_end, "from_end should not be used for array element ConstantIndex");
238240
*offset == index
239241
}
240-
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
241-
size - offset == index
242-
}
243242
_ => false,
244243
})
245244
}

0 commit comments

Comments
 (0)