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.
This commit is contained in:
parent
088b7e2108
commit
5c717a6fc2
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}));
|
||||
|
@ -1061,43 +1061,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
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,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
@ -1325,9 +1288,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
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)?;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,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.
|
||||
@ -584,31 +584,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())
|
||||
@ -660,13 +648,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]
|
||||
}
|
||||
@ -818,13 +801,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 +823,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()
|
||||
}
|
||||
@ -988,29 +970,34 @@ 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| &**p).chain(
|
||||
repeat(DUMMY_WILD_PAT).take(arity - pat_len).chain(
|
||||
after.iter().map(|p| &**p)
|
||||
)).collect())
|
||||
},
|
||||
Slice(length) if pat_len <= length && slice.is_some() => {
|
||||
Some(
|
||||
before.iter().map(|p| &**p).chain(
|
||||
repeat(DUMMY_WILD_PAT).take(arity - pat_len).chain(
|
||||
after.iter().map(|p| &**p)
|
||||
)).collect())
|
||||
}
|
||||
Slice(length) if pat_len == length => {
|
||||
Some(
|
||||
before.iter().map(|p| &**p).chain(
|
||||
after.iter().map(|p| &**p)
|
||||
).collect())
|
||||
}
|
||||
SliceWithSubslice(prefix, suffix)
|
||||
if before.len() == prefix
|
||||
&& after.len() == suffix
|
||||
&& slice.is_some() => {
|
||||
// this is used by trans::_match only
|
||||
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
|
||||
pats.extend(after.iter().map(|p| &**p));
|
||||
Some(pats)
|
||||
|
@ -429,42 +429,83 @@ 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) {
|
||||
/// (true, _) => true, // (0)
|
||||
/// (_, true) => true, // (1)
|
||||
/// (false, false) => false // (2)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 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 and 2
|
||||
/// - 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 to 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));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 => {
|
||||
|
@ -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) =>
|
||||
@ -131,7 +132,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 +170,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 +184,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.mir.lvalue_ty(tcx, lvalue).to_ty(tcx);
|
||||
let llbasety = type_of::type_of(bcx.ccx(), base_ty).ptr_to();
|
||||
let llbase = bcx.pointercast(llbase, llbasety);
|
||||
(bcx.pointercast(llbase, llbasety), 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 +219,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
ty: projected_ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
|
||||
result
|
||||
}
|
||||
|
||||
// Perform an action using the given Lvalue.
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,42 @@ 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() {
|
||||
span_err!(tcx.sess, pat.span, E0529,
|
||||
"expected an array or slice, found `{}`",
|
||||
expected_ty);
|
||||
}
|
||||
(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 +367,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 `{}`
|
||||
}
|
||||
|
@ -560,15 +560,20 @@ impl Wtf8 {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(stage0): use slice patterns after snapshot
|
||||
#[inline]
|
||||
fn final_lead_surrogate(&self) -> Option<u16> {
|
||||
let len = self.len();
|
||||
if len < 3 {
|
||||
return None
|
||||
}
|
||||
match &self.bytes[(len - 3)..] {
|
||||
[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
_ => None
|
||||
if self.bytes[len-3] == 0xed &&
|
||||
self.bytes[len-2] > 0xa0 &&
|
||||
self.bytes[len-2] <= 0xaf
|
||||
{
|
||||
Some(decode_surrogate(self.bytes[len-2], self.bytes[len-1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,9 +583,13 @@ impl Wtf8 {
|
||||
if len < 3 {
|
||||
return None
|
||||
}
|
||||
match &self.bytes[..3] {
|
||||
[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
|
||||
_ => None
|
||||
if self.bytes[len-3] == 0xed &&
|
||||
self.bytes[len-2] > 0xb0 &&
|
||||
self.bytes[len-2] <= 0xbf
|
||||
{
|
||||
Some(decode_surrogate(self.bytes[len-2], self.bytes[len-1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.., _] => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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…
x
Reference in New Issue
Block a user