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.
This commit is contained in:
parent
7de9402b77
commit
bf278ebd9d
11 changed files with 119 additions and 63 deletions
|
|
@ -1714,18 +1714,25 @@ pub enum ProjectionElem<V, T> {
|
|||
ConstantIndex {
|
||||
/// index or -index (in Python terms), depending on from_end
|
||||
offset: u32,
|
||||
/// thing being indexed must be at least this long
|
||||
/// The thing being indexed must be at least this long. For arrays this
|
||||
/// is always the exact length.
|
||||
min_length: u32,
|
||||
/// counting backwards from end?
|
||||
/// Counting backwards from end? This is always false when indexing an
|
||||
/// array.
|
||||
from_end: bool,
|
||||
},
|
||||
|
||||
/// These indices are generated by slice patterns.
|
||||
///
|
||||
/// slice[from:-to] in Python terms.
|
||||
/// If `from_end` is true `slice[from..slice.len() - to]`.
|
||||
/// Otherwise `array[from..to]`.
|
||||
Subslice {
|
||||
from: u32,
|
||||
to: u32,
|
||||
/// Whether `to` counts from the start or end of the array/slice.
|
||||
/// For `PlaceElem`s this is `true` if and only if the base is a slice.
|
||||
/// For `ProjectionKind`, this can also be `true` for arrays.
|
||||
from_end: bool,
|
||||
},
|
||||
|
||||
/// "Downcast" to a variant of an ADT. Currently, we only introduce
|
||||
|
|
@ -1914,15 +1921,18 @@ impl Debug for Place<'_> {
|
|||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
||||
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if *to == 0 => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => {
|
||||
write!(fmt, "[{:?}:]", from)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if *from == 0 => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => {
|
||||
write!(fmt, "[:-{:?}]", to)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } => {
|
||||
write!(fmt, "[{:?}:-{:?}]", from, to)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||
write!(fmt, "[{:?}..{:?}]", from, to)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2452,7 +2462,7 @@ impl UserTypeProjection {
|
|||
}
|
||||
|
||||
pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
|
||||
self.projs.push(ProjectionElem::Subslice { from, to });
|
||||
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,14 +88,17 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
}
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
|
||||
PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
PlaceTy::from_ty(match self.ty.kind {
|
||||
ty::Array(inner, size) => {
|
||||
ty::Slice(..) => self.ty,
|
||||
ty::Array(inner, _) if !from_end => {
|
||||
tcx.mk_array(inner, (to - from) as u64)
|
||||
}
|
||||
ty::Array(inner, size) if from_end => {
|
||||
let size = size.eval_usize(tcx, param_env);
|
||||
let len = size - (from as u64) - (to as u64);
|
||||
tcx.mk_array(inner, len)
|
||||
}
|
||||
ty::Slice(..) => self.ty,
|
||||
_ => {
|
||||
bug!("cannot subslice non-array type: `{:?}`", self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -954,7 +954,7 @@ macro_rules! visit_place_fns {
|
|||
);
|
||||
}
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Subslice { from: _, to: _ } |
|
||||
ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
from_end: _ } |
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let llindex = bx.sub(lllen, lloffset);
|
||||
cg_base.project_index(bx, llindex)
|
||||
}
|
||||
mir::ProjectionElem::Subslice { from, to } => {
|
||||
mir::ProjectionElem::Subslice { from, to, from_end } => {
|
||||
let mut subslice = cg_base.project_index(bx,
|
||||
bx.cx().const_usize(*from as u64));
|
||||
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
|
||||
|
|
@ -573,6 +573,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
|
||||
|
||||
if subslice.layout.is_unsized() {
|
||||
assert!(from_end, "slice subslices should be `from_end`");
|
||||
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
|
||||
bx.cx().const_usize((*from as u64) + (*to as u64))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -673,23 +673,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}),
|
||||
)
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
|
||||
ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty(
|
||||
match base_ty.kind {
|
||||
ty::Array(inner, size) => {
|
||||
let size = size.eval_usize(tcx, self.cx.param_env);
|
||||
let min_size = (from as u64) + (to as u64);
|
||||
if let Some(rest_size) = size.checked_sub(min_size) {
|
||||
tcx.mk_array(inner, rest_size)
|
||||
} else {
|
||||
span_mirbug_and_err!(
|
||||
self,
|
||||
place,
|
||||
"taking too-small slice of {:?}",
|
||||
base_ty
|
||||
)
|
||||
}
|
||||
ty::Array(inner, _) => {
|
||||
assert!(!from_end, "array subslices should not use from_end");
|
||||
tcx.mk_array(inner, (to - from) as u64)
|
||||
}
|
||||
ty::Slice(..) => base_ty,
|
||||
ty::Slice(..) => {
|
||||
assert!(from_end, "slice subslices should use from_end");
|
||||
base_ty
|
||||
},
|
||||
_ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -503,34 +503,62 @@ fn place_projection_conflict<'tcx>(
|
|||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice {from, .. })
|
||||
| (ProjectionElem::Subslice {from, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
|
||||
if offset >= from {
|
||||
debug!(
|
||||
"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
(
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice { from, to, from_end: false }
|
||||
)
|
||||
| (
|
||||
ProjectionElem::Subslice { from, to, from_end: false },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }
|
||||
) => {
|
||||
if (from..to).contains(&offset) {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
|
||||
ProjectionElem::Subslice {from: _, to })
|
||||
| (ProjectionElem::Subslice {from: _, to },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
|
||||
if offset > to {
|
||||
debug!("place_element_conflict: \
|
||||
DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice {from, .. })
|
||||
| (ProjectionElem::Subslice {from, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
|
||||
if offset >= from {
|
||||
debug!(
|
||||
"place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
|
||||
ProjectionElem::Subslice { to, .. })
|
||||
| (ProjectionElem::Subslice { to, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
|
||||
if offset > to {
|
||||
debug!("place_element_conflict: \
|
||||
DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(
|
||||
ProjectionElem::Subslice { from: f1, to: t1, from_end: false },
|
||||
ProjectionElem::Subslice { from: f2, to: t2, from_end: false }
|
||||
) => {
|
||||
if f2 >= t1 || f1 >= t2 {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
(ProjectionElem::Deref, _)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::build::Builder;
|
|||
use crate::build::matches::MatchPair;
|
||||
use crate::hair::*;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty;
|
||||
use smallvec::SmallVec;
|
||||
use std::u32;
|
||||
use std::convert::TryInto;
|
||||
|
|
@ -31,9 +32,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
prefix: &'pat [Pat<'tcx>],
|
||||
opt_slice: Option<&'pat Pat<'tcx>>,
|
||||
suffix: &'pat [Pat<'tcx>]) {
|
||||
let min_length = prefix.len() + suffix.len();
|
||||
let min_length = min_length.try_into().unwrap();
|
||||
let tcx = self.hir.tcx();
|
||||
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
|
||||
ty::Array(_, length) => (
|
||||
length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(),
|
||||
true
|
||||
),
|
||||
_ => (
|
||||
(prefix.len() + suffix.len()).try_into().unwrap(),
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
match_pairs.extend(
|
||||
prefix.iter()
|
||||
|
|
@ -50,10 +59,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
);
|
||||
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: suffix.len() as u32
|
||||
});
|
||||
let suffix_len = suffix.len() as u32;
|
||||
let subslice = tcx.mk_place_elem(
|
||||
place.clone(),
|
||||
ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
||||
from_end: !exact_size,
|
||||
},
|
||||
);
|
||||
match_pairs.push(MatchPair::new(subslice, subslice_pat));
|
||||
}
|
||||
|
||||
|
|
@ -62,10 +76,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.rev()
|
||||
.enumerate()
|
||||
.map(|(idx, subpattern)| {
|
||||
let end_offset = (idx + 1) as u32;
|
||||
let elem = ProjectionElem::ConstantIndex {
|
||||
offset: (idx+1) as u32,
|
||||
offset: if exact_size { min_length - end_offset } else { end_offset },
|
||||
min_length,
|
||||
from_end: true,
|
||||
from_end: !exact_size,
|
||||
};
|
||||
let place = tcx.mk_place_elem(place.clone(), elem);
|
||||
MatchPair::new(place, subpattern)
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
|
|||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
|
||||
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from: from, to: to }
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use core::slice::Iter;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{Ty, TyCtxt};
|
||||
use rustc::ty::{Ty, TyCtxt, ParamEnv};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_index::vec::{Enumerated, Idx, IndexVec};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -318,8 +318,9 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn gather_moves(
|
||||
body: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
|
||||
builder::gather_moves(body, tcx)
|
||||
builder::gather_moves(body, tcx, param_env)
|
||||
}
|
||||
|
||||
/// For the move path `mpi`, returns the root local variable (if any) that starts the path.
|
||||
|
|
|
|||
|
|
@ -451,9 +451,15 @@ where
|
|||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
from: u64,
|
||||
to: u64,
|
||||
from_end: bool,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
||||
assert!(from <= len - to);
|
||||
let actual_to = if from_end {
|
||||
assert!(from <= len - to);
|
||||
len - to
|
||||
} else {
|
||||
to
|
||||
};
|
||||
|
||||
// Not using layout method because that works with usize, and does not work with slices
|
||||
// (that have count 0 in their layout).
|
||||
|
|
@ -464,7 +470,7 @@ where
|
|||
};
|
||||
|
||||
// Compute meta and new layout
|
||||
let inner_len = len - to - from;
|
||||
let inner_len = actual_to - from;
|
||||
let (meta, ty) = match base.layout.ty.kind {
|
||||
// It is not nice to match on the type, but that seems to be the only way to
|
||||
// implement this.
|
||||
|
|
@ -528,8 +534,8 @@ where
|
|||
self.mplace_field(base, index)?
|
||||
}
|
||||
|
||||
Subslice { from, to } =>
|
||||
self.mplace_subslice(base, u64::from(from), u64::from(to))?,
|
||||
Subslice { from, to, from_end } =>
|
||||
self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,12 +234,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
|
|||
|
||||
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
debug_assert!(size == *min_length, "min_length should be exact for arrays");
|
||||
assert!(!from_end, "from_end should not be used for array element ConstantIndex");
|
||||
*offset == index
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
|
||||
size - offset == index
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue