non-MIR translation is still not supported for these and will happily ICE.
This is a [breaking-change] for many uses of slice_patterns.
}
}
}
- 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);
- }
_ => {}
}
}));
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>,
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)?;
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.
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),
+
},
}
}
/// 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>>,
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 {
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) => {
}
}
}
- Rvalue::Slice { .. } => None,
Rvalue::InlineAsm { .. } => None
}
}
}
}
- 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: _ } => {
match *proj {
ProjectionElem::Deref => {
}
+ ProjectionElem::Subslice { from: _, to: _ } => {
+ }
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
self.visit_ty(ty);
}
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,
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);
- }
}
}
}
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.
}
}
- 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())
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]
}
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],
/// 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()
}
}
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)
/// 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 the outcome is that `x` is true, candidates 0 and 2
+ /// - If the outcome is that `x` is false, candidates 1 and 2
///
- /// - 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.
+ /// Here, the traditional "decision tree" method would generate 2
+ /// separate code-paths for the 2 separate cases.
///
- /// 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.
+ /// 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,
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
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
/// 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 } => {
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
}
- Ok(block)
+ Ok(())
}
PatternKind::Constant { .. } => {
}
PatternKind::Range { .. } |
- PatternKind::Variant { .. } => {
- // cannot simplify, test is required
- Err(match_pair)
- }
-
- PatternKind::Slice { .. } if !match_pair.slice_len_checked => {
+ PatternKind::Variant { .. } |
+ PatternKind::Slice { .. } => {
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(())
}
}
}
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.
}
};
- 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
+ }
}
}
- // 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);
+ (&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
}
- _ => false
+ (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
+ }
}
}
- TestKind::Eq { .. } |
- TestKind::Range { .. } => {
+ (&TestKind::Eq { .. }, _) |
+ (&TestKind::Range { .. }, _) |
+ (&TestKind::Len { .. }, _) => {
// These are all binary tests.
//
// FIXME(#29623) we can be more clever here
}
}
+ 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>,
// 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::*;
.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)| {
let lvalue = lvalue.clone().elem(elem);
MatchPair::new(lvalue, subpattern)
})
- .collect();
+ );
+
+ 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));
+ }
- let suffix_pairs: Vec<_> =
+ match_pairs.extend(
suffix.iter()
.rev()
.enumerate()
let lvalue = lvalue.clone().elem(elem);
MatchPair::new(lvalue, subpattern)
})
- .collect();
-
- match_pairs.extend(prefix_pairs.into_iter().chain(suffix_pairs));
+ );
}
}
}
ProjectionElem::ConstantIndex {..} |
+ ProjectionElem::Subslice {..} |
ProjectionElem::Downcast(..) => {
this.not_const()
}
}
}
- Rvalue::Slice {..} |
Rvalue::InlineAsm {..} => {
self.not_const();
}
})
}
}
+ 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 => {
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,
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) =>
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 {
}
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,
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)
ty: projected_ty,
}
}
- }
+ };
+ debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
+ result
}
// Perform an action using the given Lvalue.
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,
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);
}
mir::Rvalue::Repeat(..) |
mir::Rvalue::Aggregate(..) |
- mir::Rvalue::Slice { .. } |
mir::Rvalue::InlineAsm { .. } => {
bug!("cannot generate operand from rvalue {:?}", rvalue);
true,
mir::Rvalue::Repeat(..) |
mir::Rvalue::Aggregate(..) |
- mir::Rvalue::Slice { .. } |
mir::Rvalue::InlineAsm { .. } =>
false,
}
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};
}
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 {
}
}
-
// (*) 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
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(()) => {}
- }
- }
_ => {}
}
});
// 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 `{}`
}
}
}
+ // 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
}
}
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
}
}
}
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
}
_ => {
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
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
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
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
}
_ => {}
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]);
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
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.
//
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
_ => {}
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
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
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
};
}
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
}
}
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)
};
}
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)
};
}
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);
}
}
fn main() {
match () {
[()] => { }
- //~^ ERROR mismatched types
- //~| expected type `()`
- //~| found type `&[_]`
- //~| expected (), found &-ptr
+ //~^ ERROR expected an array or slice, found `()`
}
}
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
+ };
}
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
_ => ()
"bar".to_string(),
"baz".to_string()];
let x: &[String] = &x;
- match x {
+ match *x {
[a, _, _, ..] => { println!("{}", a); }
[_, _, _, _, _] => { } //~ ERROR unreachable pattern
_ => { }
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
_ => {}
}
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)"
}
}
}
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] => (),
}
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] => {}
[] => {}
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
[] => (),
[_] => (),
[Enum::Second(true), Enum::First] => (),
[Enum::Second(true), Enum::Second(true)] => (),
[Enum::Second(false), _] => (),
- [_, _, tail.., _] => ()
+ [_, _, ref tail.., _] => ()
}
}
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
}
}
fn count_members(v: &[usize]) -> usize {
- match v {
+ match *v {
[] => 0,
[_] => 1,
- [_x, xs..] => 1 + count_members(xs)
+ [_, ref xs..] => 1 + count_members(xs)
}
}
// 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);
#![feature(advanced_slice_patterns)]
#![feature(slice_patterns)]
+#![feature(rustc_attrs)]
use std::ops::Add;
[a, b, b, a]
}
+#[rustc_mir]
fn main() {
assert_eq!(foo([1, 2, 3]), (1, 3, 6));
#![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"
}
}
#![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)
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
+ }
}
}
// 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);
#![feature(advanced_slice_patterns)]
#![feature(slice_patterns)]
+#![feature(rustc_attrs)]
+#[rustc_mir]
fn a() {
let x = [1];
match x {
}
}
+#[rustc_mir]
fn b() {
let x = [1, 2, 3];
match x {
}
}
+
+#[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 {
}
}
+#[rustc_mir]
fn d() {
let x = [1, 2, 3];
let branch = match x {
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();
#![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 }] => {
// 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 ())
}
}