Skip to content

Commit

Permalink
Auto merge of #32202 - arielb1:slice-patterns, r=nikomatsakis
Browse files Browse the repository at this point in the history
Implement RFC495 semantics for slice patterns

non-MIR translation is still not supported for these and will happily ICE.

This is a [breaking-change] for many uses of slice_patterns.

[RFC 495 text](https://github.com/rust-lang/rfcs/blob/master/text/0495-array-pattern-changes.md)
  • Loading branch information
bors committed Jun 9, 2016
2 parents 34505e2 + 2de6ea7 commit bb4b3fb
Show file tree
Hide file tree
Showing 77 changed files with 934 additions and 732 deletions.
6 changes: 3 additions & 3 deletions mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back rustc_data_structures\
rustc_const_math
DEPS_rustc_back := std syntax flate log libc
DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax
DEPS_rustc_borrowck := rustc log graphviz syntax rustc_mir
DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
Expand All @@ -123,9 +123,9 @@ DEPS_rustc_passes := syntax rustc core rustc_const_eval
DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags
DEPS_rustc_resolve := arena rustc log syntax
DEPS_rustc_platform_intrinsics := std
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
DEPS_rustc_plugin := rustc rustc_metadata syntax
DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm rustc_platform_intrinsics \
rustc_const_math rustc_const_eval rustc_incremental
DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures
Expand Down
6 changes: 3 additions & 3 deletions src/doc/book/slice-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() {
let v = vec!["match_this", "1"];

match &v[..] {
["match_this", second] => println!("The second element is {}", second),
&["match_this", second] => println!("The second element is {}", second),
_ => {},
}
}
Expand All @@ -26,8 +26,8 @@ slice will be bound to that name. For example:

fn is_symmetric(list: &[u32]) -> bool {
match list {
[] | [_] => true,
[x, inside.., y] if x == y => is_symmetric(inside),
&[] | &[_] => true,
&[x, ref inside.., y] if x == y => is_symmetric(inside),
_ => false
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ pub mod mir {
pub mod tcx;
pub mod visit;
pub mod transform;
pub mod traversal;
pub mod mir_map;
}

Expand Down
34 changes: 0 additions & 34 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,40 +993,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
}
}
PatKind::Vec(_, Some(ref slice_pat), _) => {
// The `slice_pat` here creates a slice into
// the original vector. This is effectively a
// borrow of the elements of the vector being
// matched.

let (slice_cmt, slice_mutbl, slice_r) =
return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));

// Note: We declare here that the borrow
// occurs upon entering the `[...]`
// pattern. This implies that something like
// `[a; b]` where `a` is a move is illegal,
// because the borrow is already in effect.
// In fact such a move would be safe-ish, but
// it effectively *requires* that we use the
// nulling out semantics to indicate when a
// value has been moved, which we are trying
// to move away from. Otherwise, how can we
// indicate that the first element in the
// vector has been moved? Eventually, we
// could perhaps modify this rule to permit
// `[..a, b]` where `b` is a move, because in
// that case we can adjust the length of the
// original vec accordingly, but we'd have to
// make trans do the right thing, and it would
// only work for `Box<[T]>`s. It seems simpler
// to just require that people call
// `vec.pop()` or `vec.unshift()`.
let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
delegate.borrow(pat.id, pat.span,
slice_cmt, slice_r,
slice_bk, RefBinding);
}
_ => {}
}
}));
Expand Down
127 changes: 11 additions & 116 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
Ok(deref_interior(InteriorField(PositionalField(0))))
}

ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
ty::TyArray(_, _) | ty::TySlice(_) => {
// no deref of indexed content without supplying InteriorOffsetKind
if let Some(context) = context {
Ok(deref_interior(InteriorElement(context, element_kind(t))))
Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
} else {
Err(())
}
Expand Down Expand Up @@ -981,121 +981,31 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let method_call = ty::MethodCall::expr(elt.id());
let method_ty = self.infcx.node_method_ty(method_call);

let element_ty = match method_ty {
let (element_ty, element_kind) = match method_ty {
Some(method_ty) => {
let ref_ty = self.overloaded_method_return_ty(method_ty);
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);

// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
let self_ty = method_ty.fn_sig().input(0);
self.tcx().no_late_bound_regions(&self_ty).unwrap()
(self.tcx().no_late_bound_regions(&self_ty).unwrap(),
ElementKind::OtherElement)
}
None => {
match base_cmt.ty.builtin_index() {
Some(ty) => ty,
Some(ty) => (ty, ElementKind::VecElement),
None => {
return Err(());
}
}
}
};

let m = base_cmt.mutbl.inherit();
let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
m, context, element_ty);
let interior_elem = InteriorElement(context, element_kind);
let ret =
self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
debug!("cat_index ret {:?}", ret);
return Ok(ret);

fn interior<'tcx, N: ast_node>(elt: &N,
of_cmt: cmt<'tcx>,
vec_ty: Ty<'tcx>,
mutbl: MutabilityCategory,
context: InteriorOffsetKind,
element_ty: Ty<'tcx>) -> cmt<'tcx>
{
let interior_elem = InteriorElement(context, element_kind(vec_ty));
Rc::new(cmt_ {
id:elt.id(),
span:elt.span(),
cat:Categorization::Interior(of_cmt, interior_elem),
mutbl:mutbl,
ty:element_ty,
note: NoteNone
})
}
}

// Takes either a vec or a reference to a vec and returns the cmt for the
// underlying vec.
fn deref_vec<N:ast_node>(&self,
elt: &N,
base_cmt: cmt<'tcx>,
context: InteriorOffsetKind)
-> McResult<cmt<'tcx>>
{
let ret = match deref_kind(base_cmt.ty, Some(context))? {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);

// the deref is explicit in the resulting cmt
Rc::new(cmt_ {
id:elt.id(),
span:elt.span(),
cat:Categorization::Deref(base_cmt.clone(), 0, ptr),
mutbl:m,
ty: match base_cmt.ty.builtin_deref(false, ty::NoPreference) {
Some(mt) => mt.ty,
None => bug!("Found non-derefable type")
},
note: NoteNone
})
}

deref_interior(_) => {
base_cmt
}
};
debug!("deref_vec ret {:?}", ret);
Ok(ret)
}

/// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
/// the pattern `Q`, returns:
///
/// * a cmt for `Q`
/// * the mutability and region of the slice `Q`
///
/// These last two bits of info happen to be things that borrowck needs.
pub fn cat_slice_pattern(&self,
vec_cmt: cmt<'tcx>,
slice_pat: &hir::Pat)
-> McResult<(cmt<'tcx>, hir::Mutability, ty::Region)> {
let slice_ty = self.node_ty(slice_pat.id)?;
let (slice_mutbl, slice_r) = vec_slice_info(slice_pat, slice_ty);
let context = InteriorOffsetKind::Pattern;
let cmt_vec = self.deref_vec(slice_pat, vec_cmt, context)?;
let cmt_slice = self.cat_index(slice_pat, cmt_vec, context)?;
return Ok((cmt_slice, slice_mutbl, slice_r));

/// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
/// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
/// have to recurse through rptrs.
fn vec_slice_info(pat: &hir::Pat, slice_ty: Ty)
-> (hir::Mutability, ty::Region) {
match slice_ty.sty {
ty::TyRef(r, ref mt) => match mt.ty.sty {
ty::TySlice(_) => (mt.mutbl, *r),
_ => vec_slice_info(pat, mt.ty),
},

_ => {
span_bug!(pat.span,
"type of slice pattern is not a slice");
}
}
}
}

pub fn cat_imm_interior<N:ast_node>(&self,
Expand Down Expand Up @@ -1319,15 +1229,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

PatKind::Vec(ref before, ref slice, ref after) => {
let context = InteriorOffsetKind::Pattern;
let vec_cmt = self.deref_vec(pat, cmt, context)?;
let elt_cmt = self.cat_index(pat, vec_cmt, context)?;
let elt_cmt = self.cat_index(pat, cmt, context)?;
for before_pat in before {
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
}
if let Some(ref slice_pat) = *slice {
let slice_ty = self.pat_ty(&slice_pat)?;
let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
self.cat_pattern_(slice_cmt, &slice_pat, op)?;
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
}
for after_pat in after {
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
Expand Down Expand Up @@ -1620,18 +1527,6 @@ impl fmt::Debug for InteriorKind {
}
}

fn element_kind(t: Ty) -> ElementKind {
match t.sty {
ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
ty::TyBox(ty) => match ty.sty {
ty::TySlice(_) => VecElement,
_ => OtherElement
},
ty::TyArray(..) | ty::TySlice(_) => VecElement,
_ => OtherElement
}
}

impl fmt::Debug for Upvar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}/{:?}", self.id, self.kind)
Expand Down
29 changes: 16 additions & 13 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,14 @@ pub enum ProjectionElem<'tcx, V> {
from_end: bool,
},

/// These indices are generated by slice patterns.
///
/// slice[from:-to] in Python terms.
Subslice {
from: u32,
to: u32,
},

/// "Downcast" to a variant of an ADT. Currently, we only introduce
/// this for ADTs with more than one variant. It may be better to
/// just introduce it always, or always for enums.
Expand Down Expand Up @@ -753,6 +761,14 @@ impl<'tcx> Debug for Lvalue<'tcx> {
write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length),
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length),
ProjectionElem::Subslice { from, to } if to == 0 =>
write!(fmt, "{:?}[{:?}:", data.base, from),
ProjectionElem::Subslice { from, to } if from == 0 =>
write!(fmt, "{:?}[:-{:?}]", data.base, to),
ProjectionElem::Subslice { from, to } =>
write!(fmt, "{:?}[{:?}:-{:?}]", data.base,
from, to),

},
}
}
Expand Down Expand Up @@ -856,17 +872,6 @@ pub enum Rvalue<'tcx> {
/// away after type-checking and before lowering.
Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),

/// Generates a slice of the form `&input[from_start..L-from_end]`
/// where `L` is the length of the slice. This is only created by
/// slice pattern matching, so e.g. a pattern of the form `[x, y,
/// .., z]` might create a slice with `from_start=2` and
/// `from_end=1`.
Slice {
input: Lvalue<'tcx>,
from_start: usize,
from_end: usize,
},

InlineAsm {
asm: InlineAsm,
outputs: Vec<Lvalue<'tcx>>,
Expand Down Expand Up @@ -972,8 +977,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
InlineAsm { ref asm, ref outputs, ref inputs } => {
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
}
Slice { ref input, from_start, from_end } =>
write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),

Ref(_, borrow_kind, ref lv) => {
let kind_str = match borrow_kind {
Expand Down
15 changes: 14 additions & 1 deletion src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
LvalueTy::Ty {
ty: self.to_ty(tcx).builtin_index().unwrap()
},
ProjectionElem::Subslice { from, to } => {
let ty = self.to_ty(tcx);
LvalueTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
tcx.mk_array(inner, size-(from as usize)-(to as usize))
}
ty::TySlice(..) => ty,
_ => {
bug!("cannot subslice non-array type: `{:?}`", self)
}
}
}
}
ProjectionElem::Downcast(adt_def1, index) =>
match self.to_ty(tcx).sty {
ty::TyEnum(adt_def, substs) => {
Expand Down Expand Up @@ -219,7 +233,6 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> {
}
}
}
Rvalue::Slice { .. } => None,
Rvalue::InlineAsm { .. } => None
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::vec;

use rustc_data_structures::bitvec::BitVector;

use rustc::mir::repr::*;
use super::repr::*;

/// Preorder traversal of a graph.
///
Expand Down
11 changes: 2 additions & 9 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,6 @@ macro_rules! make_mir_visitor {
}
}

Rvalue::Slice { ref $($mutability)* input,
from_start,
from_end } => {
self.visit_lvalue(input, LvalueContext::Slice {
from_start: from_start,
from_end: from_end,
});
}

Rvalue::InlineAsm { ref $($mutability)* outputs,
ref $($mutability)* inputs,
asm: _ } => {
Expand Down Expand Up @@ -602,6 +593,8 @@ macro_rules! make_mir_visitor {
match *proj {
ProjectionElem::Deref => {
}
ProjectionElem::Subslice { from: _, to: _ } => {
}
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
self.visit_ty(ty);
}
Expand Down
Loading

0 comments on commit bb4b3fb

Please sign in to comment.