Auto merge of #32202 - arielb1:slice-patterns, r=nikomatsakis
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)
This commit is contained in:
commit
bb4b3fb7f9
77 changed files with 940 additions and 738 deletions
|
|
@ -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 \
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ pub mod mir {
|
|||
pub mod tcx;
|
||||
pub mod visit;
|
||||
pub mod transform;
|
||||
pub mod traversal;
|
||||
pub mod mir_map;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
@ -981,18 +981,19 @@ 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(());
|
||||
}
|
||||
|
|
@ -1000,102 +1001,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
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,
|
||||
|
|
@ -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)?;
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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),
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -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>>,
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
@ -219,7 +233,6 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Slice { .. } => None,
|
||||
Rvalue::InlineAsm { .. } => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
@ -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: _ } => {
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ use session::Session;
|
|||
use traits;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use util::common::slice_pat;
|
||||
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
|
@ -98,17 +100,17 @@ impl TargetDataLayout {
|
|||
|
||||
let mut dl = TargetDataLayout::default();
|
||||
for spec in sess.target.target.data_layout.split("-") {
|
||||
match &spec.split(":").collect::<Vec<_>>()[..] {
|
||||
["e"] => dl.endian = Endian::Little,
|
||||
["E"] => dl.endian = Endian::Big,
|
||||
["a", a..] => dl.aggregate_align = align(a, "a"),
|
||||
["f32", a..] => dl.f32_align = align(a, "f32"),
|
||||
["f64", a..] => dl.f64_align = align(a, "f64"),
|
||||
[p @ "p", s, a..] | [p @ "p0", s, a..] => {
|
||||
match slice_pat(&&spec.split(":").collect::<Vec<_>>()[..]) {
|
||||
&["e"] => dl.endian = Endian::Little,
|
||||
&["E"] => dl.endian = Endian::Big,
|
||||
&["a", ref a..] => dl.aggregate_align = align(a, "a"),
|
||||
&["f32", ref a..] => dl.f32_align = align(a, "f32"),
|
||||
&["f64", ref a..] => dl.f64_align = align(a, "f64"),
|
||||
&[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => {
|
||||
dl.pointer_size = size(s, p);
|
||||
dl.pointer_align = align(a, p);
|
||||
}
|
||||
[s, a..] if s.starts_with("i") => {
|
||||
&[s, ref a..] if s.starts_with("i") => {
|
||||
let ty_align = match s[1..].parse::<u64>() {
|
||||
Ok(1) => &mut dl.i8_align,
|
||||
Ok(8) => &mut dl.i8_align,
|
||||
|
|
@ -123,7 +125,7 @@ impl TargetDataLayout {
|
|||
};
|
||||
*ty_align = align(a, s);
|
||||
}
|
||||
[s, a..] if s.starts_with("v") => {
|
||||
&[s, ref a..] if s.starts_with("v") => {
|
||||
let v_size = size(&s[1..], "v");
|
||||
let a = align(a, s);
|
||||
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
|
||||
|
|
|
|||
|
|
@ -247,3 +247,15 @@ pub fn path2cstr(p: &Path) -> CString {
|
|||
pub fn path2cstr(p: &Path) -> CString {
|
||||
CString::new(p.to_str().unwrap()).unwrap()
|
||||
}
|
||||
|
||||
// FIXME(stage0): remove this
|
||||
// HACK: this is needed because the interpretation of slice
|
||||
// patterns changed between stage0 and now.
|
||||
#[cfg(stage0)]
|
||||
pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
|
||||
t
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
|
||||
*t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ impl<'tcx> Lift for LvalueElem<'tcx> {
|
|||
ProjectionElem::Field(f.clone(), ty.clone()),
|
||||
ProjectionElem::Index(ref i) =>
|
||||
ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Subslice {from, to} =>
|
||||
ProjectionElem::Subslice { from: from, to: to },
|
||||
ProjectionElem::ConstantIndex {offset,min_length,from_end} =>
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset: offset,
|
||||
|
|
|
|||
|
|
@ -620,22 +620,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
|
|||
Rvalue::Ref(..) |
|
||||
Rvalue::Len(..) |
|
||||
Rvalue::InlineAsm { .. } => {}
|
||||
|
||||
Rvalue::Slice {..} => {
|
||||
// A slice pattern `x..` binds `x` to a
|
||||
// reference; thus no move occurs.
|
||||
//
|
||||
// FIXME: I recall arielb1 questioning
|
||||
// whether this is even a legal thing to
|
||||
// have as an R-value. The particular
|
||||
// example where I am seeing this arise is
|
||||
// `TargetDataLayout::parse(&Session)` in
|
||||
// `rustc::ty::layout`.
|
||||
//
|
||||
// this should be removed soon.
|
||||
debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?}",
|
||||
source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ use rustc::hir::fold::{Folder, noop_fold_pat};
|
|||
use rustc::hir::print::pat_to_string;
|
||||
use syntax::ptr::P;
|
||||
use rustc::util::nodemap::FnvHashMap;
|
||||
use rustc::util::common::slice_pat;
|
||||
|
||||
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
|
|
@ -49,7 +50,7 @@ pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
|
|||
span: DUMMY_SP
|
||||
};
|
||||
|
||||
struct Matrix<'a>(Vec<Vec<&'a Pat>>);
|
||||
struct Matrix<'a, 'tcx>(Vec<Vec<(&'a Pat, Option<Ty<'tcx>>)>>);
|
||||
|
||||
/// Pretty-printer for matrices of patterns, example:
|
||||
/// ++++++++++++++++++++++++++
|
||||
|
|
@ -63,14 +64,14 @@ struct Matrix<'a>(Vec<Vec<&'a Pat>>);
|
|||
/// ++++++++++++++++++++++++++
|
||||
/// + _ + [_, _, ..tail] +
|
||||
/// ++++++++++++++++++++++++++
|
||||
impl<'a> fmt::Debug for Matrix<'a> {
|
||||
impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "\n")?;
|
||||
|
||||
let &Matrix(ref m) = self;
|
||||
let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
|
||||
row.iter()
|
||||
.map(|&pat| pat_to_string(&pat))
|
||||
.map(|&(pat,ty)| format!("{}: {:?}", pat_to_string(&pat), ty))
|
||||
.collect::<Vec<String>>()
|
||||
}).collect();
|
||||
|
||||
|
|
@ -97,8 +98,10 @@ impl<'a> fmt::Debug for Matrix<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
|
||||
fn from_iter<T: IntoIterator<Item=Vec<&'a Pat>>>(iter: T) -> Matrix<'a> {
|
||||
impl<'a, 'tcx> FromIterator<Vec<(&'a Pat, Option<Ty<'tcx>>)>> for Matrix<'a, 'tcx> {
|
||||
fn from_iter<T: IntoIterator<Item=Vec<(&'a Pat, Option<Ty<'tcx>>)>>>(iter: T)
|
||||
-> Self
|
||||
{
|
||||
Matrix(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +112,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
|||
pub param_env: ParameterEnvironment<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Constructor {
|
||||
/// The constructor of all patterns that don't vary by constructor,
|
||||
/// e.g. struct patterns and fixed-length arrays.
|
||||
|
|
@ -229,7 +232,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
|
|||
.iter()
|
||||
.filter(|&&(_, guard)| guard.is_none())
|
||||
.flat_map(|arm| &arm.0)
|
||||
.map(|pat| vec![&**pat])
|
||||
.map(|pat| vec![wrap_pat(cx, &pat)])
|
||||
.collect();
|
||||
check_exhaustive(cx, ex.span, &matrix, source);
|
||||
},
|
||||
|
|
@ -301,7 +304,7 @@ fn check_arms(cx: &MatchCheckCtxt,
|
|||
let mut printed_if_let_err = false;
|
||||
for &(ref pats, guard) in arms {
|
||||
for pat in pats {
|
||||
let v = vec![&**pat];
|
||||
let v = vec![wrap_pat(cx, &pat)];
|
||||
|
||||
match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
|
||||
NotUseful => {
|
||||
|
|
@ -341,8 +344,9 @@ fn check_arms(cx: &MatchCheckCtxt,
|
|||
"unreachable pattern");
|
||||
// if we had a catchall pattern, hint at that
|
||||
for row in &seen.0 {
|
||||
if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) {
|
||||
span_note!(err, row[0].span, "this pattern matches any value");
|
||||
if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) {
|
||||
span_note!(err, row[0].0.span,
|
||||
"this pattern matches any value");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
|
@ -383,20 +387,23 @@ fn raw_pat(p: &Pat) -> &Pat {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) {
|
||||
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
|
||||
fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
sp: Span,
|
||||
matrix: &Matrix<'a, 'tcx>,
|
||||
source: hir::MatchSource) {
|
||||
match is_useful(cx, matrix, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
|
||||
UsefulWithWitness(pats) => {
|
||||
let witnesses = if pats.is_empty() {
|
||||
vec![DUMMY_WILD_PAT]
|
||||
} else {
|
||||
pats.iter().map(|w| &**w ).collect()
|
||||
pats.iter().map(|w| &**w).collect()
|
||||
};
|
||||
match source {
|
||||
hir::MatchSource::ForLoopDesugar => {
|
||||
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
|
||||
let witness = match witnesses[0].node {
|
||||
PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
|
||||
[ref pat] => &**pat,
|
||||
PatKind::TupleStruct(_, ref pats, _) => match slice_pat(&&pats[..]) {
|
||||
&[ref pat] => &**pat,
|
||||
_ => bug!(),
|
||||
},
|
||||
_ => bug!(),
|
||||
|
|
@ -584,31 +591,19 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
|
|||
}
|
||||
}
|
||||
|
||||
ty::TyRef(_, ty::TypeAndMut { ty, mutbl }) => {
|
||||
match ty.sty {
|
||||
ty::TyArray(_, n) => match ctor {
|
||||
&Single => {
|
||||
assert_eq!(pats_len, n);
|
||||
PatKind::Vec(pats.collect(), None, hir::HirVec::new())
|
||||
},
|
||||
_ => bug!()
|
||||
},
|
||||
ty::TySlice(_) => match ctor {
|
||||
&Slice(n) => {
|
||||
assert_eq!(pats_len, n);
|
||||
PatKind::Vec(pats.collect(), None, hir::HirVec::new())
|
||||
},
|
||||
_ => bug!()
|
||||
},
|
||||
ty::TyStr => PatKind::Wild,
|
||||
|
||||
_ => {
|
||||
assert_eq!(pats_len, 1);
|
||||
PatKind::Ref(pats.nth(0).unwrap(), mutbl)
|
||||
}
|
||||
}
|
||||
ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
|
||||
assert_eq!(pats_len, 1);
|
||||
PatKind::Ref(pats.nth(0).unwrap(), mutbl)
|
||||
}
|
||||
|
||||
ty::TySlice(_) => match ctor {
|
||||
&Slice(n) => {
|
||||
assert_eq!(pats_len, n);
|
||||
PatKind::Vec(pats.collect(), None, hir::HirVec::new())
|
||||
},
|
||||
_ => unreachable!()
|
||||
},
|
||||
|
||||
ty::TyArray(_, len) => {
|
||||
assert_eq!(pats_len, len);
|
||||
PatKind::Vec(pats.collect(), None, hir::HirVec::new())
|
||||
|
|
@ -643,7 +638,7 @@ impl Constructor {
|
|||
fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
|
||||
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
|
||||
let used_constructors: Vec<Constructor> = rows.iter()
|
||||
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
|
||||
.flat_map(|row| pat_constructors(cx, row[0].0, left_ty, max_slice_length))
|
||||
.collect();
|
||||
all_constructors(cx, left_ty, max_slice_length)
|
||||
.into_iter()
|
||||
|
|
@ -660,13 +655,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
|
|||
match left_ty.sty {
|
||||
ty::TyBool =>
|
||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||
|
||||
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty {
|
||||
ty::TySlice(_) =>
|
||||
(0..max_slice_length+1).map(|length| Slice(length)).collect(),
|
||||
_ => vec![Single]
|
||||
},
|
||||
|
||||
ty::TySlice(_) =>
|
||||
(0..max_slice_length+1).map(|length| Slice(length)).collect(),
|
||||
ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(),
|
||||
_ => vec![Single]
|
||||
}
|
||||
|
|
@ -685,13 +675,13 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
|
|||
|
||||
// Note: is_useful doesn't work on empty types, as the paper notes.
|
||||
// So it assumes that v is non-empty.
|
||||
fn is_useful(cx: &MatchCheckCtxt,
|
||||
matrix: &Matrix,
|
||||
v: &[&Pat],
|
||||
witness: WitnessPreference)
|
||||
-> Usefulness {
|
||||
fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
matrix: &Matrix<'a, 'tcx>,
|
||||
v: &[(&Pat, Option<Ty<'tcx>>)],
|
||||
witness: WitnessPreference)
|
||||
-> Usefulness {
|
||||
let &Matrix(ref rows) = matrix;
|
||||
debug!("{:?}", matrix);
|
||||
debug!("is_useful({:?}, {:?})", matrix, v);
|
||||
if rows.is_empty() {
|
||||
return match witness {
|
||||
ConstructWitness => UsefulWithWitness(vec!()),
|
||||
|
|
@ -702,32 +692,25 @@ fn is_useful(cx: &MatchCheckCtxt,
|
|||
return NotUseful;
|
||||
}
|
||||
assert!(rows.iter().all(|r| r.len() == v.len()));
|
||||
let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) {
|
||||
Some(r) => raw_pat(r[0]),
|
||||
None if v.is_empty() => return NotUseful,
|
||||
None => v[0]
|
||||
};
|
||||
let left_ty = if real_pat.id == DUMMY_NODE_ID {
|
||||
cx.tcx.mk_nil()
|
||||
} else {
|
||||
let left_ty = cx.tcx.pat_ty(&real_pat);
|
||||
|
||||
match real_pat.node {
|
||||
PatKind::Binding(hir::BindByRef(..), _, _) => {
|
||||
left_ty.builtin_deref(false, NoPreference).unwrap().ty
|
||||
}
|
||||
_ => left_ty,
|
||||
let left_ty = match rows.iter().filter_map(|r| r[0].1).next().or_else(|| v[0].1) {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
// all patterns are wildcards - we can pick any type we want
|
||||
cx.tcx.types.bool
|
||||
}
|
||||
};
|
||||
|
||||
let max_slice_length = rows.iter().filter_map(|row| match row[0].node {
|
||||
let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node {
|
||||
PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()),
|
||||
_ => None
|
||||
}).max().map_or(0, |v| v + 1);
|
||||
|
||||
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
|
||||
let constructors = pat_constructors(cx, v[0].0, left_ty, max_slice_length);
|
||||
debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors,
|
||||
left_ty);
|
||||
if constructors.is_empty() {
|
||||
let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
|
||||
debug!("is_useful - missing_constructors = {:?}", constructors);
|
||||
if constructors.is_empty() {
|
||||
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
|
||||
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
|
||||
|
|
@ -748,7 +731,7 @@ fn is_useful(cx: &MatchCheckCtxt,
|
|||
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
||||
} else {
|
||||
let matrix = rows.iter().filter_map(|r| {
|
||||
match raw_pat(r[0]).node {
|
||||
match raw_pat(r[0].0).node {
|
||||
PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -773,9 +756,14 @@ fn is_useful(cx: &MatchCheckCtxt,
|
|||
}
|
||||
}
|
||||
|
||||
fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix,
|
||||
v: &[&Pat], ctor: Constructor, lty: Ty,
|
||||
witness: WitnessPreference) -> Usefulness {
|
||||
fn is_useful_specialized<'a, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
&Matrix(ref m): &Matrix<'a, 'tcx>,
|
||||
v: &[(&Pat, Option<Ty<'tcx>>)],
|
||||
ctor: Constructor,
|
||||
lty: Ty<'tcx>,
|
||||
witness: WitnessPreference) -> Usefulness
|
||||
{
|
||||
let arity = constructor_arity(cx, &ctor, lty);
|
||||
let matrix = Matrix(m.iter().filter_map(|r| {
|
||||
specialize(cx, &r[..], &ctor, 0, arity)
|
||||
|
|
@ -818,13 +806,14 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
|||
PatKind::Vec(ref before, ref slice, ref after) =>
|
||||
match left_ty.sty {
|
||||
ty::TyArray(_, _) => vec![Single],
|
||||
_ => if slice.is_some() {
|
||||
ty::TySlice(_) if slice.is_some() => {
|
||||
(before.len() + after.len()..max_slice_length+1)
|
||||
.map(|length| Slice(length))
|
||||
.collect()
|
||||
} else {
|
||||
vec![Slice(before.len() + after.len())]
|
||||
}
|
||||
ty::TySlice(_) => vec!(Slice(before.len() + after.len())),
|
||||
_ => span_bug!(pat.span, "pat_constructors: unexpected \
|
||||
slice pattern type {:?}", left_ty)
|
||||
},
|
||||
PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) =>
|
||||
vec![Single],
|
||||
|
|
@ -839,18 +828,16 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
|||
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
||||
/// A struct pattern's arity is the number of fields it contains, etc.
|
||||
pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
|
||||
debug!("constructor_arity({:?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs) => fs.len(),
|
||||
ty::TyBox(_) => 1,
|
||||
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty {
|
||||
ty::TySlice(_) => match *ctor {
|
||||
Slice(length) => length,
|
||||
ConstantValue(_) => 0,
|
||||
_ => bug!()
|
||||
},
|
||||
ty::TyStr => 0,
|
||||
_ => 1
|
||||
ty::TySlice(_) => match *ctor {
|
||||
Slice(length) => length,
|
||||
ConstantValue(_) => 0,
|
||||
_ => bug!()
|
||||
},
|
||||
ty::TyRef(..) => 1,
|
||||
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
|
||||
ctor.variant_for_adt(adt).fields.len()
|
||||
}
|
||||
|
|
@ -877,6 +864,19 @@ fn range_covered_by_constructor(ctor: &Constructor,
|
|||
}
|
||||
}
|
||||
|
||||
fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
|
||||
pat: &'a Pat)
|
||||
-> (&'a Pat, Option<Ty<'tcx>>)
|
||||
{
|
||||
let pat_ty = cx.tcx.pat_ty(pat);
|
||||
(pat, Some(match pat.node {
|
||||
PatKind::Binding(hir::BindByRef(..), _, _) => {
|
||||
pat_ty.builtin_deref(false, NoPreference).unwrap().ty
|
||||
}
|
||||
_ => pat_ty
|
||||
}))
|
||||
}
|
||||
|
||||
/// This is the main specialization step. It expands the first pattern in the given row
|
||||
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
|
||||
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
|
||||
|
|
@ -885,14 +885,22 @@ fn range_covered_by_constructor(ctor: &Constructor,
|
|||
/// different patterns.
|
||||
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
||||
/// fields filled with wild patterns.
|
||||
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||
constructor: &Constructor, col: usize, arity: usize) -> Option<Vec<&'a Pat>> {
|
||||
pub fn specialize<'a, 'b, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'b, 'tcx>,
|
||||
r: &[(&'a Pat, Option<Ty<'tcx>>)],
|
||||
constructor: &Constructor, col: usize, arity: usize)
|
||||
-> Option<Vec<(&'a Pat, Option<Ty<'tcx>>)>>
|
||||
{
|
||||
let pat = raw_pat(r[col].0);
|
||||
let &Pat {
|
||||
id: pat_id, ref node, span: pat_span
|
||||
} = raw_pat(r[col]);
|
||||
let head: Option<Vec<&Pat>> = match *node {
|
||||
} = pat;
|
||||
let wpat = |pat: &'a Pat| wrap_pat(cx, pat);
|
||||
let dummy_pat = (DUMMY_WILD_PAT, None);
|
||||
|
||||
let head: Option<Vec<(&Pat, Option<Ty>)>> = match *node {
|
||||
PatKind::Binding(..) | PatKind::Wild =>
|
||||
Some(vec![DUMMY_WILD_PAT; arity]),
|
||||
Some(vec![dummy_pat; arity]),
|
||||
|
||||
PatKind::Path(..) => {
|
||||
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
||||
|
|
@ -917,12 +925,14 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
Def::Variant(..) | Def::Struct(..) => {
|
||||
match ddpos {
|
||||
Some(ddpos) => {
|
||||
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect();
|
||||
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
|
||||
pats.extend(args[ddpos..].iter().map(|p| &**p));
|
||||
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| {
|
||||
wpat(p)
|
||||
}).collect();
|
||||
pats.extend(repeat((DUMMY_WILD_PAT, None)).take(arity - args.len()));
|
||||
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
|
||||
Some(pats)
|
||||
}
|
||||
None => Some(args.iter().map(|p| &**p).collect())
|
||||
None => Some(args.iter().map(|p| wpat(p)).collect())
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
|
|
@ -941,8 +951,8 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
if variant.did == def_variant.did {
|
||||
Some(variant.fields.iter().map(|sf| {
|
||||
match pattern_fields.iter().find(|f| f.node.name == sf.name) {
|
||||
Some(ref f) => &*f.node.pat,
|
||||
_ => DUMMY_WILD_PAT
|
||||
Some(ref f) => wpat(&f.node.pat),
|
||||
_ => dummy_pat
|
||||
}
|
||||
}).collect())
|
||||
} else {
|
||||
|
|
@ -951,25 +961,32 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
}
|
||||
|
||||
PatKind::Tuple(ref args, Some(ddpos)) => {
|
||||
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect();
|
||||
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len()));
|
||||
pats.extend(args[ddpos..].iter().map(|p| &**p));
|
||||
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect();
|
||||
pats.extend(repeat(dummy_pat).take(arity - args.len()));
|
||||
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
|
||||
Some(pats)
|
||||
}
|
||||
PatKind::Tuple(ref args, None) =>
|
||||
Some(args.iter().map(|p| &**p).collect()),
|
||||
Some(args.iter().map(|p| wpat(&**p)).collect()),
|
||||
|
||||
PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) =>
|
||||
Some(vec![&**inner]),
|
||||
Some(vec![wpat(&**inner)]),
|
||||
|
||||
PatKind::Lit(ref expr) => {
|
||||
let expr_value = eval_const_expr(cx.tcx, &expr);
|
||||
match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
|
||||
Some(true) => Some(vec![]),
|
||||
Some(false) => None,
|
||||
None => {
|
||||
span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
|
||||
None
|
||||
if let Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) = r[col].1 {
|
||||
// HACK: handle string literals. A string literal pattern
|
||||
// serves both as an unary reference pattern and as a
|
||||
// nullary value pattern, depending on the type.
|
||||
Some(vec![(pat, Some(mt.ty))])
|
||||
} else {
|
||||
let expr_value = eval_const_expr(cx.tcx, &expr);
|
||||
match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
|
||||
Some(true) => Some(vec![]),
|
||||
Some(false) => None,
|
||||
None => {
|
||||
span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -988,37 +1005,45 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
}
|
||||
|
||||
PatKind::Vec(ref before, ref slice, ref after) => {
|
||||
let pat_len = before.len() + after.len();
|
||||
match *constructor {
|
||||
// Fixed-length vectors.
|
||||
Single => {
|
||||
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
||||
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
|
||||
pats.extend(after.iter().map(|p| &**p));
|
||||
Some(pats)
|
||||
},
|
||||
Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
|
||||
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
||||
pats.extend(repeat(DUMMY_WILD_PAT).take(arity - before.len() - after.len()));
|
||||
pats.extend(after.iter().map(|p| &**p));
|
||||
Some(pats)
|
||||
},
|
||||
Slice(length) if before.len() + after.len() == length => {
|
||||
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
||||
pats.extend(after.iter().map(|p| &**p));
|
||||
Some(pats)
|
||||
// Fixed-length vectors.
|
||||
Some(
|
||||
before.iter().map(|p| wpat(p)).chain(
|
||||
repeat(dummy_pat).take(arity - pat_len).chain(
|
||||
after.iter().map(|p| wpat(p))
|
||||
)).collect())
|
||||
},
|
||||
Slice(length) if pat_len <= length && slice.is_some() => {
|
||||
Some(
|
||||
before.iter().map(|p| wpat(p)).chain(
|
||||
repeat(dummy_pat).take(arity - pat_len).chain(
|
||||
after.iter().map(|p| wpat(p))
|
||||
)).collect())
|
||||
}
|
||||
Slice(length) if pat_len == length => {
|
||||
Some(
|
||||
before.iter().map(|p| wpat(p)).chain(
|
||||
after.iter().map(|p| wpat(p))
|
||||
).collect())
|
||||
}
|
||||
SliceWithSubslice(prefix, suffix)
|
||||
if before.len() == prefix
|
||||
&& after.len() == suffix
|
||||
&& slice.is_some() => {
|
||||
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
||||
pats.extend(after.iter().map(|p| &**p));
|
||||
// this is used by trans::_match only
|
||||
let mut pats: Vec<_> = before.iter()
|
||||
.map(|p| (&**p, None)).collect();
|
||||
pats.extend(after.iter().map(|p| (&**p, None)));
|
||||
Some(pats)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head);
|
||||
|
||||
head.map(|mut head| {
|
||||
head.extend_from_slice(&r[..col]);
|
||||
head.extend_from_slice(&r[col + 1..]);
|
||||
|
|
@ -1076,8 +1101,8 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
|
|||
fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A> where
|
||||
F: FnOnce(&Pat) -> A,
|
||||
{
|
||||
let pats = Matrix(vec!(vec!(pat)));
|
||||
match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) {
|
||||
let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
|
||||
match is_useful(cx, &pats, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
|
||||
UsefulWithWitness(pats) => Some(refutable(&pats[0])),
|
||||
NotUseful => None,
|
||||
Useful => bug!()
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt};
|
|||
use middle::const_val::ConstVal;
|
||||
use rustc_const_eval::eval_const_expr_partial;
|
||||
use rustc_const_eval::EvalHint::ExprTypeChecked;
|
||||
use util::common::slice_pat;
|
||||
use util::nodemap::{FnvHashSet};
|
||||
use lint::{LateContext, LintContext, LintArray};
|
||||
use lint::{LintPass, LateLintPass};
|
||||
|
|
@ -459,8 +460,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
// Check for a repr() attribute to specify the size of the
|
||||
// discriminant.
|
||||
let repr_hints = cx.lookup_repr_hints(def.did);
|
||||
match &**repr_hints {
|
||||
[] => {
|
||||
match slice_pat(&&**repr_hints) {
|
||||
&[] => {
|
||||
// Special-case types like `Option<extern fn()>`.
|
||||
if !is_repr_nullable_ptr(cx, def, substs) {
|
||||
return FfiUnsafe(
|
||||
|
|
@ -470,7 +471,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
the type")
|
||||
}
|
||||
}
|
||||
[ref hint] => {
|
||||
&[ref hint] => {
|
||||
if !hint.is_ffi_safe() {
|
||||
// FIXME: This shouldn't be reachable: we should check
|
||||
// this earlier.
|
||||
|
|
|
|||
|
|
@ -429,42 +429,87 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
/// simpler (and, in fact, irrefutable).
|
||||
///
|
||||
/// But there may also be candidates that the test just doesn't
|
||||
/// apply to. For example, consider the case of #29740:
|
||||
/// apply to. The classical example involves wildcards:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// match x {
|
||||
/// "foo" => ...,
|
||||
/// "bar" => ...,
|
||||
/// "baz" => ...,
|
||||
/// _ => ...,
|
||||
/// match (x, y, z) {
|
||||
/// (true, _, true) => true, // (0)
|
||||
/// (_, true, _) => true, // (1)
|
||||
/// (false, false, _) => false, // (2)
|
||||
/// (true, _, false) => false, // (3)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here the match-pair we are testing will be `x @ "foo"`, and we
|
||||
/// will generate an `Eq` test. Because `"bar"` and `"baz"` are different
|
||||
/// constants, we will decide that these later candidates are just not
|
||||
/// informed by the eq test. So we'll wind up with three candidate sets:
|
||||
/// In that case, after we test on `x`, there are 2 overlapping candidate
|
||||
/// sets:
|
||||
///
|
||||
/// - If outcome is that `x == "foo"` (one candidate, derived from `x @ "foo"`)
|
||||
/// - If outcome is that `x != "foo"` (empty list of candidates)
|
||||
/// - Otherwise (three candidates, `x @ "bar"`, `x @ "baz"`, `x @
|
||||
/// _`). Here we have the invariant that everything in the
|
||||
/// otherwise list is of **lower priority** than the stuff in the
|
||||
/// other lists.
|
||||
/// - If the outcome is that `x` is true, candidates 0, 1, and 3
|
||||
/// - If the outcome is that `x` is false, candidates 1 and 2
|
||||
///
|
||||
/// So we'll compile the test. For each outcome of the test, we
|
||||
/// recursively call `match_candidates` with the corresponding set
|
||||
/// of candidates. But note that this set is now inexhaustive: for
|
||||
/// example, in the case where the test returns false, there are
|
||||
/// NO candidates, even though there is stll a value to be
|
||||
/// matched. So we'll collect the return values from
|
||||
/// `match_candidates`, which are the blocks where control-flow
|
||||
/// goes if none of the candidates matched. At this point, we can
|
||||
/// continue with the "otherwise" list.
|
||||
/// Here, the traditional "decision tree" method would generate 2
|
||||
/// separate code-paths for the 2 separate cases.
|
||||
///
|
||||
/// In some cases, this duplication can create an exponential amount of
|
||||
/// code. This is most easily seen by noticing that this method terminates
|
||||
/// with precisely the reachable arms being reachable - but that problem
|
||||
/// is trivially NP-complete:
|
||||
///
|
||||
/// ```rust
|
||||
/// match (var0, var1, var2, var3, ..) {
|
||||
/// (true, _, _, false, true, ...) => false,
|
||||
/// (_, true, true, false, _, ...) => false,
|
||||
/// (false, _, false, false, _, ...) => false,
|
||||
/// ...
|
||||
/// _ => true
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here the last arm is reachable only if there is an assignment to
|
||||
/// the variables that does not match any of the literals. Therefore,
|
||||
/// compilation would take an exponential amount of time in some cases.
|
||||
///
|
||||
/// That kind of exponential worst-case might not occur in practice, but
|
||||
/// our simplistic treatment of constants and guards would make it occur
|
||||
/// in very common situations - for example #29740:
|
||||
///
|
||||
/// ```rust
|
||||
/// match x {
|
||||
/// "foo" if foo_guard => ...,
|
||||
/// "bar" if bar_guard => ...,
|
||||
/// "baz" if baz_guard => ...,
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test.
|
||||
///
|
||||
/// It might seem that we would end up with 2 disjoint candidate
|
||||
/// sets, consisting of the first candidate or the other 3, but our
|
||||
/// algorithm doesn't reason about "foo" being distinct from the other
|
||||
/// constants; it considers the latter arms to potentially match after
|
||||
/// both outcomes, which obviously leads to an exponential amount
|
||||
/// of tests.
|
||||
///
|
||||
/// To avoid these kinds of problems, our algorithm tries to ensure
|
||||
/// the amount of generated tests is linear. When we do a k-way test,
|
||||
/// we return an additional "unmatched" set alongside the obvious `k`
|
||||
/// sets. When we encounter a candidate that would be present in more
|
||||
/// than one of the sets, we put it and all candidates below it into the
|
||||
/// "unmatched" set. This ensures these `k+1` sets are disjoint.
|
||||
///
|
||||
/// After we perform our test, we branch into the appropriate candidate
|
||||
/// set and recurse with `match_candidates`. These sub-matches are
|
||||
/// obviously inexhaustive - as we discarded our otherwise set - so
|
||||
/// we set their continuation to do `match_candidates` on the
|
||||
/// "unmatched" set (which is again inexhaustive).
|
||||
///
|
||||
/// If you apply this to the above test, you basically wind up
|
||||
/// with an if-else-if chain, testing each candidate in turn,
|
||||
/// which is precisely what we want.
|
||||
///
|
||||
/// In addition to avoiding exponential-time blowups, this algorithm
|
||||
/// also has nice property that each guard and arm is only generated
|
||||
/// once.
|
||||
fn test_candidates<'pat>(&mut self,
|
||||
span: Span,
|
||||
arm_blocks: &mut ArmBlocks,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use std::mem;
|
|||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
pub fn simplify_candidate<'pat>(&mut self,
|
||||
mut block: BasicBlock,
|
||||
block: BasicBlock,
|
||||
candidate: &mut Candidate<'pat, 'tcx>)
|
||||
-> BlockAnd<()> {
|
||||
// repeatedly simplify match pairs until fixed point is reached
|
||||
|
|
@ -39,10 +39,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
|
||||
let mut progress = match_pairs.len(); // count how many were simplified
|
||||
for match_pair in match_pairs {
|
||||
match self.simplify_match_pair(block, match_pair, candidate) {
|
||||
Ok(b) => {
|
||||
block = b;
|
||||
}
|
||||
match self.simplify_match_pair(match_pair, candidate) {
|
||||
Ok(()) => {}
|
||||
Err(match_pair) => {
|
||||
candidate.match_pairs.push(match_pair);
|
||||
progress -= 1; // this one was not simplified
|
||||
|
|
@ -61,14 +59,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
/// possible, Err is returned and no changes are made to
|
||||
/// candidate.
|
||||
fn simplify_match_pair<'pat>(&mut self,
|
||||
mut block: BasicBlock,
|
||||
match_pair: MatchPair<'pat, 'tcx>,
|
||||
candidate: &mut Candidate<'pat, 'tcx>)
|
||||
-> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
|
||||
-> Result<(), MatchPair<'pat, 'tcx>> {
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Wild => {
|
||||
// nothing left to do
|
||||
Ok(block)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
|
||||
|
|
@ -87,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
|
||||
}
|
||||
|
||||
Ok(block)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Constant { .. } => {
|
||||
|
|
@ -96,37 +93,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
PatternKind::Range { .. } |
|
||||
PatternKind::Variant { .. } => {
|
||||
// cannot simplify, test is required
|
||||
PatternKind::Variant { .. } |
|
||||
PatternKind::Slice { .. } => {
|
||||
Err(match_pair)
|
||||
}
|
||||
|
||||
PatternKind::Slice { .. } if !match_pair.slice_len_checked => {
|
||||
Err(match_pair)
|
||||
}
|
||||
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } |
|
||||
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||
unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
|
||||
block,
|
||||
match_pair.lvalue.clone(),
|
||||
prefix,
|
||||
slice.as_ref(),
|
||||
suffix));
|
||||
Ok(block)
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
self.prefix_slice_suffix(&mut candidate.match_pairs,
|
||||
&match_pair.lvalue,
|
||||
prefix,
|
||||
slice.as_ref(),
|
||||
suffix);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Leaf { ref subpatterns } => {
|
||||
// tuple struct, match subpats (if any)
|
||||
candidate.match_pairs
|
||||
.extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
|
||||
Ok(block)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Deref { ref subpattern } => {
|
||||
let lvalue = match_pair.lvalue.deref();
|
||||
candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
|
||||
Ok(block)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal;
|
|||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::repr::*;
|
||||
use syntax::codemap::Span;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
/// Identifies what test is needed to decide if `match_pair` is applicable.
|
||||
|
|
@ -446,69 +447,118 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
match test.kind {
|
||||
match (&test.kind, &*match_pair.pattern.kind) {
|
||||
// If we are performing a variant switch, then this
|
||||
// informs variant patterns, but nothing else.
|
||||
TestKind::Switch { adt_def: tested_adt_def , .. } => {
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
|
||||
assert_eq!(adt_def, tested_adt_def);
|
||||
let new_candidate =
|
||||
self.candidate_after_variant_switch(match_pair_index,
|
||||
adt_def,
|
||||
variant_index,
|
||||
subpatterns,
|
||||
candidate);
|
||||
resulting_candidates[variant_index].push(new_candidate);
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
(&TestKind::Switch { adt_def: tested_adt_def, .. },
|
||||
&PatternKind::Variant { adt_def, variant_index, ref subpatterns }) => {
|
||||
assert_eq!(adt_def, tested_adt_def);
|
||||
let new_candidate =
|
||||
self.candidate_after_variant_switch(match_pair_index,
|
||||
adt_def,
|
||||
variant_index,
|
||||
subpatterns,
|
||||
candidate);
|
||||
resulting_candidates[variant_index].push(new_candidate);
|
||||
true
|
||||
}
|
||||
(&TestKind::Switch { .. }, _) => false,
|
||||
|
||||
// If we are performing a switch over integers, then this informs integer
|
||||
// equality, but nothing else.
|
||||
//
|
||||
// FIXME(#29623) we could use TestKind::Range to rule
|
||||
// FIXME(#29623) we could use PatternKind::Range to rule
|
||||
// things out here, in some cases.
|
||||
TestKind::SwitchInt { switch_ty: _, options: _, ref indices } => {
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Constant { ref value }
|
||||
if is_switch_ty(match_pair.pattern.ty) => {
|
||||
let index = indices[value];
|
||||
let new_candidate = self.candidate_without_match_pair(match_pair_index,
|
||||
candidate);
|
||||
resulting_candidates[index].push(new_candidate);
|
||||
(&TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
|
||||
&PatternKind::Constant { ref value })
|
||||
if is_switch_ty(match_pair.pattern.ty) => {
|
||||
let index = indices[value];
|
||||
let new_candidate = self.candidate_without_match_pair(match_pair_index,
|
||||
candidate);
|
||||
resulting_candidates[index].push(new_candidate);
|
||||
true
|
||||
}
|
||||
(&TestKind::SwitchInt { .. }, _) => false,
|
||||
|
||||
|
||||
(&TestKind::Len { len: test_len, op: BinOp::Eq },
|
||||
&PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
|
||||
let pat_len = (prefix.len() + suffix.len()) as u64;
|
||||
match (test_len.cmp(&pat_len), slice) {
|
||||
(Ordering::Equal, &None) => {
|
||||
// on true, min_len = len = $actual_length,
|
||||
// on false, len != $actual_length
|
||||
resulting_candidates[0].push(
|
||||
self.candidate_after_slice_test(match_pair_index,
|
||||
candidate,
|
||||
prefix,
|
||||
slice.as_ref(),
|
||||
suffix)
|
||||
);
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
(Ordering::Less, _) => {
|
||||
// test_len < pat_len. If $actual_len = test_len,
|
||||
// then $actual_len < pat_len and we don't have
|
||||
// enough elements.
|
||||
resulting_candidates[1].push(candidate.clone());
|
||||
true
|
||||
}
|
||||
(Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
|
||||
// This can match both if $actual_len = test_len >= pat_len,
|
||||
// and if $actual_len > test_len. We can't advance.
|
||||
false
|
||||
}
|
||||
(Ordering::Greater, &None) => {
|
||||
// test_len != pat_len, so if $actual_len = test_len, then
|
||||
// $actual_len != pat_len.
|
||||
resulting_candidates[1].push(candidate.clone());
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(&TestKind::Len { len: test_len, op: BinOp::Ge },
|
||||
&PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
|
||||
// the test is `$actual_len >= test_len`
|
||||
let pat_len = (prefix.len() + suffix.len()) as u64;
|
||||
match (test_len.cmp(&pat_len), slice) {
|
||||
(Ordering::Equal, &Some(_)) => {
|
||||
// $actual_len >= test_len = pat_len,
|
||||
// so we can match.
|
||||
resulting_candidates[0].push(
|
||||
self.candidate_after_slice_test(match_pair_index,
|
||||
candidate,
|
||||
prefix,
|
||||
slice.as_ref(),
|
||||
suffix)
|
||||
);
|
||||
true
|
||||
}
|
||||
(Ordering::Less, _) | (Ordering::Equal, &None) => {
|
||||
// test_len <= pat_len. If $actual_len < test_len,
|
||||
// then it is also < pat_len, so the test passing is
|
||||
// necessary (but insufficient).
|
||||
resulting_candidates[0].push(candidate.clone());
|
||||
true
|
||||
}
|
||||
(Ordering::Greater, &None) => {
|
||||
// test_len > pat_len. If $actual_len >= test_len > pat_len,
|
||||
// then we know we won't have a match.
|
||||
resulting_candidates[1].push(candidate.clone());
|
||||
true
|
||||
}
|
||||
(Ordering::Greater, &Some(_)) => {
|
||||
// test_len < pat_len, and is therefore less
|
||||
// strict. This can still go both ways.
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are performing a length check, then this
|
||||
// informs slice patterns, but nothing else.
|
||||
TestKind::Len { .. } => {
|
||||
let pattern_test = self.test(&match_pair);
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Slice { .. } if pattern_test.kind == test.kind => {
|
||||
let mut new_candidate = candidate.clone();
|
||||
|
||||
// Set up the MatchKind to simplify this like an array.
|
||||
new_candidate.match_pairs[match_pair_index]
|
||||
.slice_len_checked = true;
|
||||
resulting_candidates[0].push(new_candidate);
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
TestKind::Eq { .. } |
|
||||
TestKind::Range { .. } => {
|
||||
(&TestKind::Eq { .. }, _) |
|
||||
(&TestKind::Range { .. }, _) |
|
||||
(&TestKind::Len { .. }, _) => {
|
||||
// These are all binary tests.
|
||||
//
|
||||
// FIXME(#29623) we can be more clever here
|
||||
|
|
@ -544,6 +594,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn candidate_after_slice_test<'pat>(&mut self,
|
||||
match_pair_index: usize,
|
||||
candidate: &Candidate<'pat, 'tcx>,
|
||||
prefix: &'pat [Pattern<'tcx>],
|
||||
opt_slice: Option<&'pat Pattern<'tcx>>,
|
||||
suffix: &'pat [Pattern<'tcx>])
|
||||
-> Candidate<'pat, 'tcx> {
|
||||
let mut new_candidate =
|
||||
self.candidate_without_match_pair(match_pair_index, candidate);
|
||||
self.prefix_slice_suffix(
|
||||
&mut new_candidate.match_pairs,
|
||||
&candidate.match_pairs[match_pair_index].lvalue,
|
||||
prefix,
|
||||
opt_slice,
|
||||
suffix);
|
||||
|
||||
new_candidate
|
||||
}
|
||||
|
||||
fn candidate_after_variant_switch<'pat>(&mut self,
|
||||
match_pair_index: usize,
|
||||
adt_def: ty::AdtDef<'tcx>,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use build::Builder;
|
||||
use build::matches::MatchPair;
|
||||
use hair::*;
|
||||
use rustc::mir::repr::*;
|
||||
|
|
@ -28,64 +28,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// When processing an array/slice pattern like `lv @ [x, y, ..s, z]`,
|
||||
/// this function converts the prefix (`x`, `y`) and suffix (`z`) into
|
||||
/// distinct match pairs:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// lv[0 of 3] @ x // see ProjectionElem::ConstantIndex (and its Debug impl)
|
||||
/// lv[1 of 3] @ y // to explain the `[x of y]` notation
|
||||
/// lv[-1 of 3] @ z
|
||||
/// ```
|
||||
///
|
||||
/// If a slice like `s` is present, then the function also creates
|
||||
/// a temporary like:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// tmp0 = lv[2..-1] // using the special Rvalue::Slice
|
||||
/// ```
|
||||
///
|
||||
/// and creates a match pair `tmp0 @ s`
|
||||
pub fn prefix_suffix_slice<'pat>(&mut self,
|
||||
pub fn prefix_slice_suffix<'pat>(&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
|
||||
block: BasicBlock,
|
||||
lvalue: Lvalue<'tcx>,
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
prefix: &'pat [Pattern<'tcx>],
|
||||
opt_slice: Option<&'pat Pattern<'tcx>>,
|
||||
suffix: &'pat [Pattern<'tcx>])
|
||||
-> BlockAnd<()> {
|
||||
// If there is a `..P` pattern, create a temporary `t0` for
|
||||
// the slice and then a match pair `t0 @ P`:
|
||||
if let Some(slice) = opt_slice {
|
||||
let prefix_len = prefix.len();
|
||||
let suffix_len = suffix.len();
|
||||
let rvalue = Rvalue::Slice {
|
||||
input: lvalue.clone(),
|
||||
from_start: prefix_len,
|
||||
from_end: suffix_len,
|
||||
};
|
||||
let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy
|
||||
let source_info = self.source_info(slice.span);
|
||||
self.cfg.push_assign(block, source_info, &temp, rvalue);
|
||||
match_pairs.push(MatchPair::new(temp, slice));
|
||||
}
|
||||
|
||||
self.prefix_suffix(match_pairs, lvalue, prefix, suffix);
|
||||
|
||||
block.unit()
|
||||
}
|
||||
|
||||
/// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
|
||||
fn prefix_suffix<'pat>(&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
|
||||
lvalue: Lvalue<'tcx>,
|
||||
prefix: &'pat [Pattern<'tcx>],
|
||||
suffix: &'pat [Pattern<'tcx>]) {
|
||||
suffix: &'pat [Pattern<'tcx>]) {
|
||||
let min_length = prefix.len() + suffix.len();
|
||||
assert!(min_length < u32::MAX as usize);
|
||||
let min_length = min_length as u32;
|
||||
|
||||
let prefix_pairs: Vec<_> =
|
||||
match_pairs.extend(
|
||||
prefix.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, subpattern)| {
|
||||
|
|
@ -97,9 +50,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let lvalue = lvalue.clone().elem(elem);
|
||||
MatchPair::new(lvalue, subpattern)
|
||||
})
|
||||
.collect();
|
||||
);
|
||||
|
||||
let suffix_pairs: Vec<_> =
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let subslice = lvalue.clone().elem(ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: suffix.len() as u32
|
||||
});
|
||||
match_pairs.push(MatchPair::new(subslice, subslice_pat));
|
||||
}
|
||||
|
||||
match_pairs.extend(
|
||||
suffix.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
|
|
@ -112,9 +73,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let lvalue = lvalue.clone().elem(elem);
|
||||
MatchPair::new(lvalue, subpattern)
|
||||
})
|
||||
.collect();
|
||||
|
||||
match_pairs.extend(prefix_pairs.into_iter().chain(suffix_pairs));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,4 +49,3 @@ mod hair;
|
|||
pub mod mir_map;
|
||||
pub mod pretty;
|
||||
pub mod transform;
|
||||
pub mod traversal;
|
||||
|
|
|
|||
|
|
@ -11,11 +11,9 @@
|
|||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::repr::*;
|
||||
use rustc::mir::transform::{MirPass, MirSource, Pass};
|
||||
|
||||
use rustc::mir::traversal;
|
||||
use pretty;
|
||||
|
||||
use traversal;
|
||||
|
||||
pub struct AddCallGuards;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@
|
|||
|
||||
use rustc::mir::repr::*;
|
||||
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use build::Location;
|
||||
use traversal::ReversePostorder;
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use rustc::ty::cast::CastTy;
|
|||
use rustc::mir::repr::*;
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::mir::transform::{Pass, MirMapPass, MirSource};
|
||||
use rustc::mir::traversal::{self, ReversePostorder};
|
||||
use rustc::mir::visit::{LvalueContext, Visitor};
|
||||
use rustc::util::nodemap::DefIdMap;
|
||||
use syntax::abi::Abi;
|
||||
|
|
@ -35,7 +36,6 @@ use std::collections::hash_map::Entry;
|
|||
use std::fmt;
|
||||
|
||||
use build::Location;
|
||||
use traversal::{self, ReversePostorder};
|
||||
|
||||
use super::promote_consts::{self, Candidate, TempState};
|
||||
|
||||
|
|
@ -509,6 +509,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
ProjectionElem::ConstantIndex {..} |
|
||||
ProjectionElem::Subslice {..} |
|
||||
ProjectionElem::Downcast(..) => {
|
||||
this.not_const()
|
||||
}
|
||||
|
|
@ -708,7 +709,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::Slice {..} |
|
||||
Rvalue::InlineAsm {..} => {
|
||||
self.not_const();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ use rustc::middle::const_val::ConstVal;
|
|||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::repr::*;
|
||||
use rustc::mir::transform::{MirPass, MirSource, Pass};
|
||||
use rustc::mir::traversal;
|
||||
use pretty;
|
||||
use std::mem;
|
||||
|
||||
use super::remove_dead_blocks::RemoveDeadBlocks;
|
||||
|
||||
use traversal;
|
||||
|
||||
pub struct SimplifyCfg;
|
||||
|
||||
impl SimplifyCfg {
|
||||
|
|
|
|||
|
|
@ -203,6 +203,26 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
LvalueTy::Ty {
|
||||
ty: match base_ty.sty {
|
||||
ty::TyArray(inner, size) => {
|
||||
let min_size = (from as usize) + (to as usize);
|
||||
if let Some(rest_size) = size.checked_sub(min_size) {
|
||||
tcx.mk_array(inner, rest_size)
|
||||
} else {
|
||||
span_mirbug_and_err!(
|
||||
self, lvalue, "taking too-small slice of {:?}", base_ty)
|
||||
}
|
||||
}
|
||||
ty::TySlice(..) => base_ty,
|
||||
_ => {
|
||||
span_mirbug_and_err!(
|
||||
self, lvalue, "slice of non-array {:?}", base_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Downcast(adt_def1, index) =>
|
||||
match base_ty.sty {
|
||||
ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => {
|
||||
|
|
|
|||
|
|
@ -14,5 +14,4 @@ rustc = { path = "../librustc" }
|
|||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@
|
|||
extern crate rustc;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_mir;
|
||||
|
||||
pub use self::registry::Registry;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ rustc_const_math = { path = "../librustc_const_math" }
|
|||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
rustc_llvm = { path = "../librustc_llvm" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
|
||||
serialize = { path = "../libserialize" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
|
|
|||
|
|
@ -505,14 +505,16 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
val: MatchInput,
|
||||
mut e: F)
|
||||
-> Vec<Match<'a, 'p, 'blk, 'tcx>> where
|
||||
F: FnMut(&[&'p hir::Pat]) -> Option<Vec<&'p hir::Pat>>,
|
||||
F: FnMut(&[(&'p hir::Pat, Option<Ty<'tcx>>)])
|
||||
-> Option<Vec<(&'p hir::Pat, Option<Ty<'tcx>>)>>,
|
||||
{
|
||||
debug!("enter_match(bcx={}, m={:?}, col={}, val={:?})",
|
||||
bcx.to_str(), m, col, val);
|
||||
let _indenter = indenter();
|
||||
|
||||
m.iter().filter_map(|br| {
|
||||
e(&br.pats).map(|pats| {
|
||||
let pats : Vec<_> = br.pats.iter().map(|p| (*p, None)).collect();
|
||||
e(&pats).map(|pats| {
|
||||
let this = br.pats[col];
|
||||
let mut bound_ptrs = br.bound_ptrs.clone();
|
||||
match this.node {
|
||||
|
|
@ -530,7 +532,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
_ => {}
|
||||
}
|
||||
Match {
|
||||
pats: pats,
|
||||
pats: pats.into_iter().map(|p| p.0).collect(),
|
||||
data: br.data,
|
||||
bound_ptrs: bound_ptrs,
|
||||
pat_renaming_map: br.pat_renaming_map,
|
||||
|
|
@ -550,7 +552,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
// Collect all of the matches that can match against anything.
|
||||
enter_match(bcx, m, col, val, |pats| {
|
||||
match pats[col].node {
|
||||
match pats[col].0.node {
|
||||
PatKind::Binding(..) | PatKind::Wild => {
|
||||
let mut r = pats[..col].to_vec();
|
||||
r.extend_from_slice(&pats[col + 1..]);
|
||||
|
|
@ -729,7 +731,14 @@ fn bind_subslice_pat(bcx: Block,
|
|||
let (base, len) = vec_datum.get_vec_base_and_len(bcx);
|
||||
|
||||
let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
|
||||
let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
|
||||
let diff = offset_left + offset_right;
|
||||
if let ty::TyArray(ty, n) = vec_ty_contents.sty {
|
||||
let array_ty = bcx.tcx().mk_array(ty, n-diff);
|
||||
let llty_array = type_of::type_of(bcx.ccx(), array_ty);
|
||||
return PointerCast(bcx, slice_begin, llty_array.ptr_to());
|
||||
}
|
||||
|
||||
let slice_len_offset = C_uint(bcx.ccx(), diff);
|
||||
let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None);
|
||||
let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased),
|
||||
bcx.tcx().mk_slice(unit_ty));
|
||||
|
|
@ -1205,7 +1214,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
Some(field_vals)
|
||||
} else if any_uniq_pat(m, col) || any_region_pat(m, col) {
|
||||
Some(vec!(Load(bcx, val.val)))
|
||||
let ptr = if type_is_fat_ptr(bcx.tcx(), left_ty) {
|
||||
val.val
|
||||
} else {
|
||||
Load(bcx, val.val)
|
||||
};
|
||||
Some(vec!(ptr))
|
||||
} else {
|
||||
match left_ty.sty {
|
||||
ty::TyArray(_, n) => {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ extern crate rustc_back;
|
|||
extern crate rustc_data_structures;
|
||||
extern crate rustc_incremental;
|
||||
pub extern crate rustc_llvm as llvm;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_platform_intrinsics as intrinsics;
|
||||
extern crate serialize;
|
||||
extern crate rustc_const_math;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_data_structures::bitvec::BitVector;
|
|||
use rustc::mir::repr as mir;
|
||||
use rustc::mir::repr::TerminatorKind;
|
||||
use rustc::mir::visit::{Visitor, LvalueContext};
|
||||
use rustc_mir::traversal;
|
||||
use rustc::mir::traversal;
|
||||
use common::{self, Block, BlockAndBuilder};
|
||||
use super::rvalue;
|
||||
|
||||
|
|
|
|||
|
|
@ -775,9 +775,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
let dest = match *dest {
|
||||
mir::Lvalue::Temp(idx) => {
|
||||
let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), dest);
|
||||
let lvalue_ty = bcx.monomorphize(&lvalue_ty);
|
||||
let ret_ty = lvalue_ty.to_ty(bcx.tcx());
|
||||
let ret_ty = self.lvalue_ty(dest);
|
||||
match self.temps[idx as usize] {
|
||||
TempRef::Lvalue(dest) => dest,
|
||||
TempRef::Operand(None) => {
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
|
|||
use consts;
|
||||
use machine;
|
||||
use type_of::type_of;
|
||||
use type_of;
|
||||
use Disr;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use super::{MirContext, TempRef};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct LvalueRef<'tcx> {
|
||||
/// Pointer to the contents of the lvalue
|
||||
pub llval: ValueRef,
|
||||
|
|
@ -88,7 +89,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let fcx = bcx.fcx();
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
match *lvalue {
|
||||
let result = match *lvalue {
|
||||
mir::Lvalue::Var(index) => self.vars[index as usize],
|
||||
mir::Lvalue::Temp(index) => match self.temps[index as usize] {
|
||||
TempRef::Lvalue(lvalue) =>
|
||||
|
|
@ -98,8 +99,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
},
|
||||
mir::Lvalue::Arg(index) => self.args[index as usize],
|
||||
mir::Lvalue::Static(def_id) => {
|
||||
let const_ty = self.mir.lvalue_ty(tcx, lvalue);
|
||||
LvalueRef::new_sized(consts::get_static(ccx, def_id).val, const_ty)
|
||||
let const_ty = self.lvalue_ty(lvalue);
|
||||
LvalueRef::new_sized(consts::get_static(ccx, def_id).val,
|
||||
LvalueTy::from_ty(const_ty))
|
||||
},
|
||||
mir::Lvalue::ReturnPointer => {
|
||||
let llval = if !fcx.fn_ty.ret.is_ignore() {
|
||||
|
|
@ -131,7 +133,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let zero = common::C_uint(bcx.ccx(), 0u64);
|
||||
bcx.inbounds_gep(tr_base.llval, &[zero, llindex])
|
||||
};
|
||||
(element, ptr::null_mut())
|
||||
element
|
||||
};
|
||||
|
||||
let (llprojected, llextra) = match projection.elem {
|
||||
|
|
@ -169,13 +171,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
mir::ProjectionElem::Index(ref index) => {
|
||||
let index = self.trans_operand(bcx, index);
|
||||
project_index(self.prepare_index(bcx, index.immediate()))
|
||||
(project_index(self.prepare_index(bcx, index.immediate())), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: false,
|
||||
min_length: _ } => {
|
||||
let lloffset = C_uint(bcx.ccx(), offset);
|
||||
project_index(self.prepare_index(bcx, lloffset))
|
||||
(project_index(lloffset), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: true,
|
||||
|
|
@ -183,7 +185,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let lloffset = C_uint(bcx.ccx(), offset);
|
||||
let lllen = tr_base.len(bcx.ccx());
|
||||
let llindex = bcx.sub(lllen, lloffset);
|
||||
project_index(self.prepare_index(bcx, llindex))
|
||||
(project_index(llindex), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::Subslice { from, to } => {
|
||||
let llindex = C_uint(bcx.ccx(), from);
|
||||
let llbase = project_index(llindex);
|
||||
|
||||
let base_ty = tr_base.ty.to_ty(bcx.tcx());
|
||||
match base_ty.sty {
|
||||
ty::TyArray(..) => {
|
||||
// must cast the lvalue pointer type to the new
|
||||
// array type (*[%_; new_len]).
|
||||
let base_ty = self.lvalue_ty(lvalue);
|
||||
let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
|
||||
let llbase = bcx.pointercast(llbase, llbasety);
|
||||
(llbase, ptr::null_mut())
|
||||
}
|
||||
ty::TySlice(..) => {
|
||||
assert!(tr_base.llextra != ptr::null_mut());
|
||||
let lllen = bcx.sub(tr_base.llextra,
|
||||
C_uint(bcx.ccx(), from+to));
|
||||
(llbase, lllen)
|
||||
}
|
||||
_ => bug!("unexpected type {:?} in Subslice", base_ty)
|
||||
}
|
||||
}
|
||||
mir::ProjectionElem::Downcast(..) => {
|
||||
(tr_base.llval, tr_base.llextra)
|
||||
|
|
@ -195,7 +220,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
ty: projected_ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
|
||||
result
|
||||
}
|
||||
|
||||
// Perform an action using the given Lvalue.
|
||||
|
|
@ -210,27 +237,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
match self.temps[idx as usize] {
|
||||
TempRef::Lvalue(lvalue) => f(self, lvalue),
|
||||
TempRef::Operand(None) => {
|
||||
let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
|
||||
let lvalue_ty = bcx.monomorphize(&lvalue_ty);
|
||||
let lvalue_ty = self.lvalue_ty(lvalue);
|
||||
let lvalue = LvalueRef::alloca(bcx,
|
||||
lvalue_ty.to_ty(bcx.tcx()),
|
||||
lvalue_ty,
|
||||
"lvalue_temp");
|
||||
let ret = f(self, lvalue);
|
||||
let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx()));
|
||||
let op = self.trans_load(bcx, lvalue.llval, lvalue_ty);
|
||||
self.temps[idx as usize] = TempRef::Operand(Some(op));
|
||||
ret
|
||||
}
|
||||
TempRef::Operand(Some(_)) => {
|
||||
let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
|
||||
let lvalue_ty = bcx.monomorphize(&lvalue_ty);
|
||||
|
||||
// See comments in TempRef::new_operand as to why
|
||||
// we always have Some in a ZST TempRef::Operand.
|
||||
let ty = lvalue_ty.to_ty(bcx.tcx());
|
||||
let ty = self.lvalue_ty(lvalue);
|
||||
if common::type_is_zero_size(bcx.ccx(), ty) {
|
||||
// Pass an undef pointer as no stores can actually occur.
|
||||
let llptr = C_undef(type_of(bcx.ccx(), ty).ptr_to());
|
||||
f(self, LvalueRef::new_sized(llptr, lvalue_ty))
|
||||
f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty)))
|
||||
} else {
|
||||
bug!("Lvalue temp already set");
|
||||
}
|
||||
|
|
@ -264,4 +287,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
llindex
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
|
||||
let tcx = self.fcx.ccx.tcx();
|
||||
let lvalue_ty = self.mir.lvalue_ty(tcx, lvalue);
|
||||
self.fcx.monomorphize(&lvalue_ty.to_ty(tcx))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use rustc_data_structures::bitvec::BitVector;
|
|||
pub use self::constant::trans_static_initializer;
|
||||
|
||||
use self::lvalue::{LvalueRef, get_dataptr, get_meta};
|
||||
use rustc_mir::traversal;
|
||||
use rustc::mir::traversal;
|
||||
|
||||
use self::operand::{OperandRef, OperandValue};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use Disr;
|
|||
use super::MirContext;
|
||||
use super::constant::const_scalar_checked_binop;
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::lvalue::{LvalueRef, get_dataptr, get_meta};
|
||||
use super::lvalue::{LvalueRef, get_dataptr};
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
pub fn trans_rvalue(&mut self,
|
||||
|
|
@ -170,26 +170,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::Slice { ref input, from_start, from_end } => {
|
||||
let ccx = bcx.ccx();
|
||||
let input = self.trans_lvalue(&bcx, input);
|
||||
let ty = input.ty.to_ty(bcx.tcx());
|
||||
let (llbase1, lllen) = match ty.sty {
|
||||
ty::TyArray(_, n) => {
|
||||
(bcx.gepi(input.llval, &[0, from_start]), C_uint(ccx, n))
|
||||
}
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
(bcx.gepi(input.llval, &[from_start]), input.llextra)
|
||||
}
|
||||
_ => bug!("cannot slice {}", ty)
|
||||
};
|
||||
let adj = C_uint(ccx, from_start + from_end);
|
||||
let lllen1 = bcx.sub(lllen, adj);
|
||||
bcx.store(llbase1, get_dataptr(&bcx, dest.llval));
|
||||
bcx.store(lllen1, get_meta(&bcx, dest.llval));
|
||||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||
let outputs = outputs.iter().map(|output| {
|
||||
let lvalue = self.trans_lvalue(&bcx, output);
|
||||
|
|
@ -498,7 +478,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
mir::Rvalue::Repeat(..) |
|
||||
mir::Rvalue::Aggregate(..) |
|
||||
mir::Rvalue::Slice { .. } |
|
||||
mir::Rvalue::InlineAsm { .. } => {
|
||||
bug!("cannot generate operand from rvalue {:?}", rvalue);
|
||||
|
||||
|
|
@ -652,7 +631,6 @@ pub fn rvalue_creates_operand<'bcx, 'tcx>(_mir: &mir::Mir<'tcx>,
|
|||
true,
|
||||
mir::Rvalue::Repeat(..) |
|
||||
mir::Rvalue::Aggregate(..) |
|
||||
mir::Rvalue::Slice { .. } |
|
||||
mir::Rvalue::InlineAsm { .. } =>
|
||||
false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
bcx
|
||||
}
|
||||
TempRef::Operand(Some(_)) => {
|
||||
let ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
|
||||
let ty = bcx.monomorphize(&ty.to_ty(bcx.tcx()));
|
||||
let ty = self.lvalue_ty(lvalue);
|
||||
|
||||
if !common::type_is_zero_size(bcx.ccx(), ty) {
|
||||
span_bug!(statement.source_info.span,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ use lint;
|
|||
use util::nodemap::FnvHashMap;
|
||||
use session::Session;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::cmp;
|
||||
use std::ops::Deref;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
|
|
@ -323,44 +323,53 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
PatKind::Vec(ref before, ref slice, ref after) => {
|
||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||
let inner_ty = self.next_ty_var();
|
||||
let pat_ty = match expected_ty.sty {
|
||||
ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
|
||||
let (inner_ty, slice_ty) = match expected_ty.sty {
|
||||
ty::TyArray(inner_ty, size) => {
|
||||
let min_len = before.len() + after.len();
|
||||
match *slice {
|
||||
Some(_) => cmp::max(min_len, size),
|
||||
None => min_len
|
||||
if slice.is_none() {
|
||||
if min_len != size {
|
||||
span_err!(tcx.sess, pat.span, E0527,
|
||||
"pattern requires {} elements but array has {}",
|
||||
min_len, size);
|
||||
}
|
||||
(inner_ty, tcx.types.err)
|
||||
} else if let Some(rest) = size.checked_sub(min_len) {
|
||||
(inner_ty, tcx.mk_array(inner_ty, rest))
|
||||
} else {
|
||||
span_err!(tcx.sess, pat.span, E0528,
|
||||
"pattern requires at least {} elements but array has {}",
|
||||
min_len, size);
|
||||
(inner_ty, tcx.types.err)
|
||||
}
|
||||
}),
|
||||
}
|
||||
ty::TySlice(inner_ty) => (inner_ty, expected_ty),
|
||||
_ => {
|
||||
let region = self.next_region_var(infer::PatternRegion(pat.span));
|
||||
tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
|
||||
ty: tcx.mk_slice(inner_ty),
|
||||
mutbl: expected_ty.builtin_deref(true, ty::NoPreference)
|
||||
.map_or(hir::MutImmutable, |mt| mt.mutbl)
|
||||
})
|
||||
if !expected_ty.references_error() {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess, pat.span, E0529,
|
||||
"expected an array or slice, found `{}`",
|
||||
expected_ty);
|
||||
if let ty::TyRef(_, ty::TypeAndMut { mutbl: _, ty }) = expected_ty.sty {
|
||||
match ty.sty {
|
||||
ty::TyArray(..) | ty::TySlice(..) => {
|
||||
err.help("the semantics of slice patterns changed \
|
||||
recently; see issue #23121");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
(tcx.types.err, tcx.types.err)
|
||||
}
|
||||
};
|
||||
|
||||
self.write_ty(pat.id, pat_ty);
|
||||
|
||||
// `demand::subtype` would be good enough, but using
|
||||
// `eqtype` turns out to be equally general. See (*)
|
||||
// below for details.
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
self.write_ty(pat.id, expected_ty);
|
||||
|
||||
for elt in before {
|
||||
self.check_pat(&elt, inner_ty);
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
let region = self.next_region_var(infer::PatternRegion(pat.span));
|
||||
let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
|
||||
.map_or(hir::MutImmutable, |mt| mt.mutbl);
|
||||
|
||||
let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
|
||||
ty: tcx.mk_slice(inner_ty),
|
||||
mutbl: mutbl
|
||||
});
|
||||
self.check_pat(&slice, slice_ty);
|
||||
}
|
||||
for elt in after {
|
||||
|
|
@ -369,7 +378,6 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// (*) In most of the cases above (literals and constants being
|
||||
// the exception), we relate types using strict equality, evewn
|
||||
// though subtyping would be sufficient. There are a few reasons
|
||||
|
|
|
|||
|
|
@ -1157,25 +1157,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
|
||||
discr_cmt,
|
||||
root_pat);
|
||||
let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
|
||||
let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
|
||||
match sub_pat.node {
|
||||
// `ref x` pattern
|
||||
PatKind::Binding(hir::BindByRef(mutbl), _, _) => {
|
||||
self.link_region_from_node_type(sub_pat.span, sub_pat.id,
|
||||
mutbl, sub_cmt);
|
||||
}
|
||||
|
||||
// `[_, ..slice, _]` pattern
|
||||
PatKind::Vec(_, Some(ref slice_pat), _) => {
|
||||
match mc.cat_slice_pattern(sub_cmt, &slice_pat) {
|
||||
Ok((slice_cmt, slice_mutbl, slice_r)) => {
|
||||
self.link_region(sub_pat.span, &slice_r,
|
||||
ty::BorrowKind::from_mutbl(slice_mutbl),
|
||||
slice_cmt);
|
||||
}
|
||||
Err(()) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4139,5 +4139,8 @@ register_diagnostics! {
|
|||
// type `{}` was overridden
|
||||
E0436, // functional record update requires a struct
|
||||
E0513, // no type for local variable ..
|
||||
E0521 // redundant default implementations of trait
|
||||
E0521, // redundant default implementations of trait
|
||||
E0527, // expected {} elements, found {}
|
||||
E0528, // expected at least {} elements, found {}
|
||||
E0529, // slice pattern expects array or slice, not `{}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::hir::print as pprust;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::subst;
|
||||
use rustc::util::common::slice_pat;
|
||||
|
||||
use rustc_const_eval::lookup_const_by_id;
|
||||
|
||||
|
|
@ -197,10 +198,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let variant = tcx.lookup_adt_def(did).struct_variant();
|
||||
|
||||
clean::Struct {
|
||||
struct_type: match &*variant.fields {
|
||||
[] => doctree::Unit,
|
||||
[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype,
|
||||
[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
|
||||
struct_type: match slice_pat(&&*variant.fields) {
|
||||
&[] => doctree::Unit,
|
||||
&[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype,
|
||||
&[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
|
||||
_ => doctree::Plain,
|
||||
},
|
||||
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use std::iter::repeat;
|
|||
|
||||
use rustc::middle::cstore::LOCAL_CRATE;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::util::common::slice_pat;
|
||||
use syntax::abi::Abi;
|
||||
use rustc::hir;
|
||||
|
||||
|
|
@ -474,9 +475,9 @@ impl fmt::Display for clean::Type {
|
|||
decl.decl)
|
||||
}
|
||||
clean::Tuple(ref typs) => {
|
||||
match &**typs {
|
||||
[] => primitive_link(f, clean::PrimitiveTuple, "()"),
|
||||
[ref one] => {
|
||||
match slice_pat(&&**typs) {
|
||||
&[] => primitive_link(f, clean::PrimitiveTuple, "()"),
|
||||
&[ref one] => {
|
||||
primitive_link(f, clean::PrimitiveTuple, "(")?;
|
||||
write!(f, "{},", one)?;
|
||||
primitive_link(f, clean::PrimitiveTuple, ")")
|
||||
|
|
|
|||
|
|
@ -467,3 +467,15 @@ pub mod __rand {
|
|||
// the rustdoc documentation for primitive types. Using `include!`
|
||||
// because rustdoc only looks for these modules at the crate level.
|
||||
include!("primitive_docs.rs");
|
||||
|
||||
// FIXME(stage0): remove this after a snapshot
|
||||
// HACK: this is needed because the interpretation of slice
|
||||
// patterns changed between stage0 and now.
|
||||
#[cfg(stage0)]
|
||||
fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
|
||||
t
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
|
||||
*t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,15 +265,18 @@ mod tests {
|
|||
|
||||
// Ensure the borrowchecker works
|
||||
match queue.peek() {
|
||||
Some(vec) => match &**vec {
|
||||
// Note that `pop` is not allowed here due to borrow
|
||||
[1] => {}
|
||||
_ => return
|
||||
Some(vec) => {
|
||||
assert_eq!(&*vec, &[1]);
|
||||
},
|
||||
None => unreachable!()
|
||||
}
|
||||
|
||||
queue.pop();
|
||||
match queue.pop() {
|
||||
Some(vec) => {
|
||||
assert_eq!(&*vec, &[1]);
|
||||
},
|
||||
None => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -566,8 +566,8 @@ impl Wtf8 {
|
|||
if len < 3 {
|
||||
return None
|
||||
}
|
||||
match &self.bytes[(len - 3)..] {
|
||||
[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
match ::slice_pat(&&self.bytes[(len - 3)..]) {
|
||||
&[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
@ -578,8 +578,8 @@ impl Wtf8 {
|
|||
if len < 3 {
|
||||
return None
|
||||
}
|
||||
match &self.bytes[..3] {
|
||||
[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
match ::slice_pat(&&self.bytes[..3]) {
|
||||
&[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,10 +117,10 @@ impl Drop for FindNextFileHandle {
|
|||
|
||||
impl DirEntry {
|
||||
fn new(root: &Arc<PathBuf>, wfd: &c::WIN32_FIND_DATAW) -> Option<DirEntry> {
|
||||
match &wfd.cFileName[0..3] {
|
||||
match ::slice_pat(&&wfd.cFileName[0..3]) {
|
||||
// check for '.' and '..'
|
||||
[46, 0, ..] |
|
||||
[46, 46, 0, ..] => return None,
|
||||
&[46, 0, ..] |
|
||||
&[46, 46, 0, ..] => return None,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
|||
2
src/rustc/Cargo.lock
generated
2
src/rustc/Cargo.lock
generated
|
|
@ -238,7 +238,6 @@ dependencies = [
|
|||
"rustc_back 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
]
|
||||
|
||||
|
|
@ -285,7 +284,6 @@ dependencies = [
|
|||
"rustc_data_structures 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"rustc_platform_intrinsics 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ pub fn main() {
|
|||
Foo { string: "baz".to_string() }
|
||||
);
|
||||
let x: &[Foo] = &x;
|
||||
match x {
|
||||
[_, tail..] => {
|
||||
match *x {
|
||||
[_, ref tail..] => {
|
||||
match tail {
|
||||
[Foo { string: a },
|
||||
&[Foo { string: a },
|
||||
//~^ ERROR cannot move out of borrowed content
|
||||
//~| cannot move out
|
||||
//~| to prevent move
|
||||
Foo { string: b }] => {
|
||||
Foo { string: b }] => {
|
||||
//~^ NOTE and here
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ fn a<'a>() -> &'a [isize] {
|
|||
let vec = vec!(1, 2, 3, 4);
|
||||
let vec: &[isize] = &vec; //~ ERROR does not live long enough
|
||||
let tail = match vec {
|
||||
[_, tail..] => tail,
|
||||
&[_, ref tail..] => tail,
|
||||
_ => panic!("a")
|
||||
};
|
||||
tail
|
||||
|
|
@ -25,7 +25,7 @@ fn b<'a>() -> &'a [isize] {
|
|||
let vec = vec!(1, 2, 3, 4);
|
||||
let vec: &[isize] = &vec; //~ ERROR does not live long enough
|
||||
let init = match vec {
|
||||
[init.., _] => init,
|
||||
&[ref init.., _] => init,
|
||||
_ => panic!("b")
|
||||
};
|
||||
init
|
||||
|
|
@ -35,7 +35,7 @@ fn c<'a>() -> &'a [isize] {
|
|||
let vec = vec!(1, 2, 3, 4);
|
||||
let vec: &[isize] = &vec; //~ ERROR does not live long enough
|
||||
let slice = match vec {
|
||||
[_, slice.., _] => slice,
|
||||
&[_, ref slice.., _] => slice,
|
||||
_ => panic!("c")
|
||||
};
|
||||
slice
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn a() {
|
|||
let mut v = vec!(1, 2, 3);
|
||||
let vb: &mut [isize] = &mut v;
|
||||
match vb {
|
||||
[_a, tail..] => {
|
||||
&mut [_a, ref tail..] => {
|
||||
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
fn main() {
|
||||
let mut a = [1, 2, 3, 4];
|
||||
let t = match a {
|
||||
[1, 2, tail..] => tail,
|
||||
[1, 2, ref tail..] => tail,
|
||||
_ => unreachable!()
|
||||
};
|
||||
println!("t[0]: {}", t[0]);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ fn b() {
|
|||
let mut vec = vec!(box 1, box 2, box 3);
|
||||
let vec: &mut [Box<isize>] = &mut vec;
|
||||
match vec {
|
||||
[_b..] => {
|
||||
&mut [ref _b..] => {
|
||||
//~^ borrow of `vec[..]` occurs here
|
||||
vec[0] = box 4; //~ ERROR cannot assign
|
||||
//~^ assignment to borrowed `vec[..]` occurs here
|
||||
|
|
@ -40,10 +40,11 @@ fn c() {
|
|||
let mut vec = vec!(box 1, box 2, box 3);
|
||||
let vec: &mut [Box<isize>] = &mut vec;
|
||||
match vec {
|
||||
[_a, //~ ERROR cannot move out
|
||||
//~| cannot move out
|
||||
//~| to prevent move
|
||||
_b..] => {
|
||||
&mut [_a, //~ ERROR cannot move out of borrowed content
|
||||
//~| cannot move out
|
||||
//~| to prevent move
|
||||
..
|
||||
] => {
|
||||
// Note: `_a` is *moved* here, but `b` is borrowing,
|
||||
// hence illegal.
|
||||
//
|
||||
|
|
@ -61,7 +62,7 @@ fn d() {
|
|||
let mut vec = vec!(box 1, box 2, box 3);
|
||||
let vec: &mut [Box<isize>] = &mut vec;
|
||||
match vec {
|
||||
[_a.., //~ ERROR cannot move out
|
||||
&mut [ //~ ERROR cannot move out
|
||||
//~^ cannot move out
|
||||
_b] => {} //~ NOTE to prevent move
|
||||
_ => {}
|
||||
|
|
@ -75,7 +76,7 @@ fn e() {
|
|||
let mut vec = vec!(box 1, box 2, box 3);
|
||||
let vec: &mut [Box<isize>] = &mut vec;
|
||||
match vec {
|
||||
[_a, _b, _c] => {} //~ ERROR cannot move out
|
||||
&mut [_a, _b, _c] => {} //~ ERROR cannot move out
|
||||
//~| cannot move out
|
||||
//~| NOTE to prevent move
|
||||
//~| NOTE and here
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn a<'a>() -> &'a isize {
|
|||
let vec = vec!(1, 2, 3, 4);
|
||||
let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough
|
||||
let tail = match vec {
|
||||
[_a, tail..] => &tail[0],
|
||||
&[_a, ref tail..] => &tail[0],
|
||||
_ => panic!("foo")
|
||||
};
|
||||
tail
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
fn main() {
|
||||
let sl = vec![1,2,3];
|
||||
let v: isize = match &*sl {
|
||||
[] => 0,
|
||||
[a,b,c] => 3,
|
||||
[a, rest..] => a,
|
||||
[10,a, rest..] => 10 //~ ERROR: unreachable pattern
|
||||
&[] => 0,
|
||||
&[a,b,c] => 3,
|
||||
&[a, ref rest..] => a,
|
||||
&[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,15 @@
|
|||
|
||||
fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
|
||||
match (l1, l2) {
|
||||
([], []) => println!("both empty"),
|
||||
([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"),
|
||||
//~^ ERROR: cannot move out of borrowed content
|
||||
(&[], &[]) => println!("both empty"),
|
||||
(&[], &[hd, ..]) | (&[hd, ..], &[])
|
||||
=> println!("one empty"),
|
||||
//~^^ ERROR: cannot move out of borrowed content
|
||||
([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"),
|
||||
//~^ ERROR: cannot move out of borrowed content
|
||||
//~^^^ ERROR: cannot move out of borrowed content
|
||||
(&[hd1, ..], &[hd2, ..])
|
||||
=> println!("both nonempty"),
|
||||
//~^^ ERROR: cannot move out of borrowed content
|
||||
//~^^^ ERROR: cannot move out of borrowed content
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@
|
|||
fn main() {
|
||||
let x = [1,2];
|
||||
let y = match x {
|
||||
[] => None,
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `[_#1i; 2]`
|
||||
//~| found type `[_#7t; 0]`
|
||||
//~| expected an array with a fixed size of 2 elements, found one with 0 elements
|
||||
[] => None, //~ ERROR pattern requires 0 elements but array has 2
|
||||
[a,_] => Some(a)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,7 @@
|
|||
fn main() {
|
||||
let x = [1,2];
|
||||
let y = match x {
|
||||
[] => None,
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `[_; 2]`
|
||||
//~| found type `[_; 0]`
|
||||
//~| expected an array with a fixed size of 2 elements
|
||||
[] => None, //~ ERROR pattern requires 0 elements but array has 2
|
||||
[a,_] => Some(a)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
fn main() {
|
||||
let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
|
||||
|
||||
for [x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
|
||||
//~^ ERROR refutable pattern in `for` loop binding: `[]` not covered
|
||||
for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
|
||||
//~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
|
||||
println!("y={}", y);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
src/test/compile-fail/issue-30240.rs
Normal file
21
src/test/compile-fail/issue-30240.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
match "world" { //~ ERROR non-exhaustive patterns: `&_`
|
||||
"hello" => {}
|
||||
}
|
||||
|
||||
match "world" { //~ ERROR non-exhaustive patterns: `&_`
|
||||
ref _x if false => {}
|
||||
"hello" => {}
|
||||
"hello" => {} //~ ERROR unreachable pattern
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,6 @@
|
|||
fn main() {
|
||||
match () {
|
||||
[()] => { }
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `()`
|
||||
//~| found type `&[_]`
|
||||
//~| expected (), found &-ptr
|
||||
//~^ ERROR expected an array or slice, found `()`
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,36 @@
|
|||
|
||||
fn main() {
|
||||
match "foo".to_string() {
|
||||
['f', 'o', ..] => {} //~ ERROR mismatched types
|
||||
['f', 'o', ..] => {}
|
||||
//~^ ERROR expected an array or slice, found `std::string::String`
|
||||
_ => { }
|
||||
}
|
||||
};
|
||||
|
||||
match &[0, 1, 2] {
|
||||
[..] => {} //~ ERROR expected an array or slice, found `&[_; 3]`
|
||||
};
|
||||
|
||||
match &[0, 1, 2] {
|
||||
&[..] => {} // ok
|
||||
};
|
||||
|
||||
match [0, 1, 2] {
|
||||
[0] => {}, //~ ERROR pattern requires
|
||||
|
||||
[0, 1, x..] => {
|
||||
let a: [_; 1] = x;
|
||||
}
|
||||
[0, 1, 2, 3, x..] => {} //~ ERROR pattern requires
|
||||
};
|
||||
|
||||
match does_not_exist { //~ ERROR unresolved name
|
||||
[] => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn another_fn_to_avoid_suppression() {
|
||||
match Default::default()
|
||||
{
|
||||
[] => {} //~ ERROR the type of this value
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
fn main() {
|
||||
let x: Vec<(isize, isize)> = Vec::new();
|
||||
let x: &[(isize, isize)] = &x;
|
||||
match x {
|
||||
match *x {
|
||||
[a, (2, 3), _] => (),
|
||||
[(1, 2), (2, 3), b] => (), //~ ERROR unreachable pattern
|
||||
_ => ()
|
||||
|
|
@ -23,7 +23,7 @@ fn main() {
|
|||
"bar".to_string(),
|
||||
"baz".to_string()];
|
||||
let x: &[String] = &x;
|
||||
match x {
|
||||
match *x {
|
||||
[a, _, _, ..] => { println!("{}", a); }
|
||||
[_, _, _, _, _] => { } //~ ERROR unreachable pattern
|
||||
_ => { }
|
||||
|
|
@ -31,8 +31,8 @@ fn main() {
|
|||
|
||||
let x: Vec<char> = vec!('a', 'b', 'c');
|
||||
let x: &[char] = &x;
|
||||
match x {
|
||||
['a', 'b', 'c', _tail..] => {}
|
||||
match *x {
|
||||
['a', 'b', 'c', ref _tail..] => {}
|
||||
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ enum t { a(u), b }
|
|||
enum u { c, d }
|
||||
|
||||
fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
|
||||
match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some([]), Err(_))` not covered
|
||||
(Some([]), Ok([])) => "Some(empty), Ok(empty)",
|
||||
(Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
|
||||
(None, Ok([_, _, ..])) => "None, Ok(at least two elements)"
|
||||
match (l1, l2) { //~ ERROR non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
|
||||
(Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
|
||||
(Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
|
||||
(None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,20 +39,20 @@ fn main() {
|
|||
}
|
||||
let vec = vec!(Some(42), None, Some(21));
|
||||
let vec: &[Option<isize>] = &vec;
|
||||
match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
|
||||
[Some(..), None, tail..] => {}
|
||||
[Some(..), Some(..), tail..] => {}
|
||||
match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
|
||||
[Some(..), None, ref tail..] => {}
|
||||
[Some(..), Some(..), ref tail..] => {}
|
||||
[None] => {}
|
||||
}
|
||||
let vec = vec!(1);
|
||||
let vec: &[isize] = &vec;
|
||||
match vec {
|
||||
[_, tail..] => (),
|
||||
match *vec {
|
||||
[_, ref tail..] => (),
|
||||
[] => ()
|
||||
}
|
||||
let vec = vec!(0.5f32);
|
||||
let vec: &[f32] = &vec;
|
||||
match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
|
||||
match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
|
||||
[0.1, 0.2, 0.3] => (),
|
||||
[0.1, 0.2] => (),
|
||||
[0.1] => (),
|
||||
|
|
@ -60,11 +60,11 @@ fn main() {
|
|||
}
|
||||
let vec = vec!(Some(42), None, Some(21));
|
||||
let vec: &[Option<isize>] = &vec;
|
||||
match vec {
|
||||
[Some(..), None, tail..] => {}
|
||||
[Some(..), Some(..), tail..] => {}
|
||||
[None, None, tail..] => {}
|
||||
[None, Some(..), tail..] => {}
|
||||
match *vec {
|
||||
[Some(..), None, ref tail..] => {}
|
||||
[Some(..), Some(..), ref tail..] => {}
|
||||
[None, None, ref tail..] => {}
|
||||
[None, Some(..), ref tail..] => {}
|
||||
[Some(_)] => {}
|
||||
[None] => {}
|
||||
[] => {}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ enum Enum {
|
|||
|
||||
fn vectors_with_nested_enums() {
|
||||
let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
|
||||
match x {
|
||||
match *x {
|
||||
//~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
|
||||
[] => (),
|
||||
[_] => (),
|
||||
|
|
@ -88,7 +88,7 @@ fn vectors_with_nested_enums() {
|
|||
[Enum::Second(true), Enum::First] => (),
|
||||
[Enum::Second(true), Enum::Second(true)] => (),
|
||||
[Enum::Second(false), _] => (),
|
||||
[_, _, tail.., _] => ()
|
||||
[_, _, ref tail.., _] => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
22
src/test/compile-fail/pat-slice-old-style.rs
Normal file
22
src/test/compile-fail/pat-slice-old-style.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn slice_pat(x: &[u8]) {
|
||||
// OLD!
|
||||
match x {
|
||||
[a, b..] => {}
|
||||
//~^ ERROR expected an array or slice, found `&[u8]`
|
||||
//~| HELP the semantics of slice patterns changed recently; see issue #23121
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -16,12 +16,12 @@ fn main() {
|
|||
|
||||
let mut result = vec!();
|
||||
loop {
|
||||
x = match x {
|
||||
[1, n, 3, rest..] => {
|
||||
x = match *x {
|
||||
[1, n, 3, ref rest..] => {
|
||||
result.push(n);
|
||||
rest
|
||||
}
|
||||
[n, rest..] => {
|
||||
[n, ref rest..] => {
|
||||
result.push(n);
|
||||
rest
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ fn main() {
|
|||
}
|
||||
|
||||
fn count_members(v: &[usize]) -> usize {
|
||||
match v {
|
||||
match *v {
|
||||
[] => 0,
|
||||
[_] => 1,
|
||||
[_x, xs..] => 1 + count_members(xs)
|
||||
[_, ref xs..] => 1 + count_members(xs)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@
|
|||
// except according to those terms.
|
||||
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_patterns, rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn main() {
|
||||
let x: (isize, &[isize]) = (2, &[1, 2]);
|
||||
assert_eq!(match x {
|
||||
(0, [_, _]) => 0,
|
||||
(0, &[_, _]) => 0,
|
||||
(1, _) => 1,
|
||||
(2, [_, _]) => 2,
|
||||
(2, &[_, _]) => 2,
|
||||
(2, _) => 3,
|
||||
_ => 4
|
||||
}, 2);
|
||||
|
|
|
|||
23
src/test/run-pass/issue-30240.rs
Normal file
23
src/test/run-pass/issue-30240.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let &ref a = &[0i32] as &[_];
|
||||
assert_eq!(a, &[0i32] as &[_]);
|
||||
|
||||
let &ref a = "hello";
|
||||
assert_eq!(a, "hello");
|
||||
|
||||
match "foo" {
|
||||
"fool" => unreachable!(),
|
||||
"foo" => {},
|
||||
ref _x => unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#![feature(advanced_slice_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] {
|
|||
[a, b, b, a]
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn main() {
|
||||
assert_eq!(foo([1, 2, 3]), (1, 3, 6));
|
||||
|
||||
|
|
|
|||
18
src/test/run-pass/match-unsized.rs
Normal file
18
src/test/run-pass/match-unsized.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let data: &'static str = "Hello, World!";
|
||||
match data {
|
||||
&ref xs => {
|
||||
assert_eq!(data, xs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,47 +11,53 @@
|
|||
|
||||
#![feature(advanced_slice_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
|
||||
match (l1, l2) {
|
||||
([], []) => "both empty",
|
||||
([], [..]) | ([..], []) => "one empty",
|
||||
([..], [..]) => "both non-empty"
|
||||
(&[], &[]) => "both empty",
|
||||
(&[], &[..]) | (&[..], &[]) => "one empty",
|
||||
(&[..], &[..]) => "both non-empty"
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
|
||||
match (l1, l2) {
|
||||
([], []) => "both empty",
|
||||
([], [_, ..]) | ([_, ..], []) => "one empty",
|
||||
([_, ..], [_, ..]) => "both non-empty"
|
||||
(&[], &[]) => "both empty",
|
||||
(&[], &[_, ..]) | (&[_, ..], &[]) => "one empty",
|
||||
(&[_, ..], &[_, ..]) => "both non-empty"
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
|
||||
match (l1, l2) {
|
||||
([], []) => "both empty",
|
||||
([], [.., _]) | ([.., _], []) => "one empty",
|
||||
([.., _], [.., _]) => "both non-empty"
|
||||
(&[], &[]) => "both empty",
|
||||
(&[], &[.., _]) | (&[.., _], &[]) => "one empty",
|
||||
(&[.., _], &[.., _]) => "both non-empty"
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
|
||||
match (l1, l2) {
|
||||
(Some([]), Ok([])) => "Some(empty), Ok(empty)",
|
||||
(Some([_, ..]), Ok(_)) | (Some([_, ..]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
|
||||
(None, Ok([_, _, ..])) => "None, Ok(at least two elements)",
|
||||
(Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
|
||||
(Some(&[_, ..]), Ok(_)) | (Some(&[_, ..]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
|
||||
(None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
|
||||
_ => "other"
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn match_nested_vecs_snoc<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
|
||||
match (l1, l2) {
|
||||
(Some([]), Ok([])) => "Some(empty), Ok(empty)",
|
||||
(Some([.., _]), Ok(_)) | (Some([.., _]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok([])) | (None, Err(())) | (None, Ok([_])) => "None, Ok(less than one element)",
|
||||
(None, Ok([.., _, _])) => "None, Ok(at least two elements)",
|
||||
(Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
|
||||
(Some(&[.., _]), Ok(_)) | (Some(&[.., _]), Err(())) => "Some(non-empty), any",
|
||||
(None, Ok(&[])) | (None, Err(())) | (None, Ok(&[_])) => "None, Ok(less than one element)",
|
||||
(None, Ok(&[.., _, _])) => "None, Ok(at least two elements)",
|
||||
_ => "other"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,21 +11,28 @@
|
|||
|
||||
#![feature(advanced_slice_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[rustc_mir(graphviz="mir.gv")]
|
||||
fn foldl<T, U, F>(values: &[T],
|
||||
initial: U,
|
||||
mut function: F)
|
||||
-> U where
|
||||
U: Clone,
|
||||
U: Clone+Debug, T:Debug,
|
||||
F: FnMut(U, &T) -> U,
|
||||
{
|
||||
match values {
|
||||
[ref head, tail..] =>
|
||||
{ match values {
|
||||
&[ref head, ref tail..] =>
|
||||
foldl(tail, function(initial, head), function),
|
||||
[] => initial.clone()
|
||||
&[] => {
|
||||
// FIXME: call guards
|
||||
let res = initial.clone(); res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn foldr<T, U, F>(values: &[T],
|
||||
initial: U,
|
||||
mut function: F)
|
||||
|
|
@ -34,9 +41,12 @@ fn foldr<T, U, F>(values: &[T],
|
|||
F: FnMut(&T, U) -> U,
|
||||
{
|
||||
match values {
|
||||
[head.., ref tail] =>
|
||||
&[ref head.., ref tail] =>
|
||||
foldr(head, function(tail, initial), function),
|
||||
[] => initial.clone()
|
||||
&[] => {
|
||||
// FIXME: call guards
|
||||
let res = initial.clone(); res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_patterns, rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
pub fn main() {
|
||||
let x = &[1, 2, 3, 4, 5];
|
||||
let x: &[isize] = &[1, 2, 3, 4, 5];
|
||||
if !x.is_empty() {
|
||||
let el = match x {
|
||||
[1, ref tail..] => &tail[0],
|
||||
&[1, ref tail..] => &tail[0],
|
||||
_ => unreachable!()
|
||||
};
|
||||
println!("{}", *el);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
#![feature(advanced_slice_patterns)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn a() {
|
||||
let x = [1];
|
||||
match x {
|
||||
|
|
@ -21,6 +23,7 @@ fn a() {
|
|||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn b() {
|
||||
let x = [1, 2, 3];
|
||||
match x {
|
||||
|
|
@ -56,6 +59,48 @@ fn b() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[rustc_mir]
|
||||
fn b_slice() {
|
||||
let x : &[_] = &[1, 2, 3];
|
||||
match x {
|
||||
&[a, b, ref c..] => {
|
||||
assert_eq!(a, 1);
|
||||
assert_eq!(b, 2);
|
||||
let expected: &[_] = &[3];
|
||||
assert_eq!(c, expected);
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
match x {
|
||||
&[ref a.., b, c] => {
|
||||
let expected: &[_] = &[1];
|
||||
assert_eq!(a, expected);
|
||||
assert_eq!(b, 2);
|
||||
assert_eq!(c, 3);
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
match x {
|
||||
&[a, ref b.., c] => {
|
||||
assert_eq!(a, 1);
|
||||
let expected: &[_] = &[2];
|
||||
assert_eq!(b, expected);
|
||||
assert_eq!(c, 3);
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
match x {
|
||||
&[a, b, c] => {
|
||||
assert_eq!(a, 1);
|
||||
assert_eq!(b, 2);
|
||||
assert_eq!(c, 3);
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn c() {
|
||||
let x = [1];
|
||||
match x {
|
||||
|
|
@ -64,6 +109,7 @@ fn c() {
|
|||
}
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn d() {
|
||||
let x = [1, 2, 3];
|
||||
let branch = match x {
|
||||
|
|
@ -75,17 +121,40 @@ fn d() {
|
|||
assert_eq!(branch, 1);
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn e() {
|
||||
let x: &[isize] = &[1, 2, 3];
|
||||
match x {
|
||||
[1, 2] => (),
|
||||
[..] => ()
|
||||
}
|
||||
let a = match *x {
|
||||
[1, 2] => 0,
|
||||
[..] => 1,
|
||||
};
|
||||
|
||||
assert_eq!(a, 1);
|
||||
|
||||
let b = match *x {
|
||||
[2, ..] => 0,
|
||||
[1, 2, ..] => 1,
|
||||
[_] => 2,
|
||||
[..] => 3
|
||||
};
|
||||
|
||||
assert_eq!(b, 1);
|
||||
|
||||
|
||||
let c = match *x {
|
||||
[_, _, _, _, ..] => 0,
|
||||
[1, 2, ..] => 1,
|
||||
[_] => 2,
|
||||
[..] => 3
|
||||
};
|
||||
|
||||
assert_eq!(c, 1);
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
a();
|
||||
b();
|
||||
b_slice();
|
||||
c();
|
||||
d();
|
||||
e();
|
||||
|
|
|
|||
|
|
@ -11,26 +11,28 @@
|
|||
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
struct Foo {
|
||||
string: String
|
||||
string: &'static str
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
pub fn main() {
|
||||
let x = [
|
||||
Foo { string: "foo".to_string() },
|
||||
Foo { string: "bar".to_string() },
|
||||
Foo { string: "baz".to_string() }
|
||||
Foo { string: "foo" },
|
||||
Foo { string: "bar" },
|
||||
Foo { string: "baz" }
|
||||
];
|
||||
match x {
|
||||
[ref first, tail..] => {
|
||||
assert_eq!(first.string, "foo".to_string());
|
||||
[ref first, ref tail..] => {
|
||||
assert_eq!(first.string, "foo");
|
||||
assert_eq!(tail.len(), 2);
|
||||
assert_eq!(tail[0].string, "bar".to_string());
|
||||
assert_eq!(tail[1].string, "baz".to_string());
|
||||
assert_eq!(tail[0].string, "bar");
|
||||
assert_eq!(tail[1].string, "baz");
|
||||
|
||||
match tail {
|
||||
[Foo { .. }, _, Foo { .. }, _tail..] => {
|
||||
match *(tail as &[_]) {
|
||||
[Foo { .. }, _, Foo { .. }, ref _tail..] => {
|
||||
unreachable!();
|
||||
}
|
||||
[Foo { string: ref a }, Foo { string: ref b }] => {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn main() {
|
||||
let x = [(), ()];
|
||||
|
||||
// The subslice used to go out of bounds for zero-sized array items, check that this doesn't
|
||||
// happen anymore
|
||||
match x {
|
||||
[_, y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
|
||||
[_, ref y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue