]> git.lizzy.rs Git - rust.git/commitdiff
implement RFC495 semantics for slice patterns
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Fri, 11 Mar 2016 10:54:59 +0000 (12:54 +0200)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Wed, 8 Jun 2016 21:38:38 +0000 (00:38 +0300)
non-MIR translation is still not supported for these and will happily ICE.

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

47 files changed:
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/mem_categorization.rs
src/librustc/mir/repr.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc_borrowck/borrowck/mir/abs_domain.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_const_eval/check_match.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/simplify.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/matches/util.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/diagnostics.rs
src/libstd/sys/common/wtf8.rs
src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs
src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs
src/test/compile-fail/borrowck/borrowck-vec-pattern-move-tail.rs
src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs
src/test/compile-fail/issue-12369.rs
src/test/compile-fail/issue-12567.rs
src/test/compile-fail/issue-13482-2.rs
src/test/compile-fail/issue-13482.rs
src/test/compile-fail/issue-15381.rs
src/test/compile-fail/match-vec-mismatch-2.rs
src/test/compile-fail/match-vec-mismatch.rs
src/test/compile-fail/match-vec-unreachable.rs
src/test/compile-fail/non-exhaustive-match-nested.rs
src/test/compile-fail/non-exhaustive-match.rs
src/test/compile-fail/non-exhaustive-pattern-witness.rs
src/test/run-pass/issue-15080.rs
src/test/run-pass/issue-15104.rs
src/test/run-pass/issue-16648.rs
src/test/run-pass/issue-7784.rs
src/test/run-pass/match-vec-alternatives.rs
src/test/run-pass/vec-matching-fold.rs
src/test/run-pass/vec-matching-legal-tail-element-borrow.rs
src/test/run-pass/vec-matching.rs
src/test/run-pass/vec-tail-matching.rs
src/test/run-pass/zero_sized_subslice_match.rs

index 48b5420dd6be7e7e4c8b113a5e24e87834bd7a97..ba93e8976771602761dc797a963a97c9fe0733cb 100644 (file)
@@ -993,40 +993,6 @@ fn walk_pat(&mut self,
                         }
                     }
                 }
-                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);
-                }
                 _ => {}
             }
         }));
index 31e3db51f55d859db24bb4a87ca3f068036f5778..fc76c00aaf1e36c75758dadb71542a76904d4273 100644 (file)
@@ -1061,43 +1061,6 @@ fn deref_vec<N:ast_node>(&self,
         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 @@ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F)
                   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)?;
index e6c22d0ea3446076fe097d915197d34694068bac..7aaaf38400e878586d1e3476e5817a4dfd107e14 100644 (file)
@@ -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 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
                         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 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
             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 {
index d0ac98a79587abf643317dcc1636e7382f9d98a3..270e33c48f1a0b411b8f38374621eced24ee14ed 100644 (file)
@@ -59,6 +59,20 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, '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 @@ pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     }
                 }
             }
-            Rvalue::Slice { .. } => None,
             Rvalue::InlineAsm { .. } => None
         }
     }
index dbe48d6b09447735b02605c44ef9e4871184d060..22b3caf6d0c0ff6e60f8668bccc788452fa3b3eb 100644 (file)
@@ -533,15 +533,6 @@ fn super_rvalue(&mut self,
                         }
                     }
 
-                    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 @@ fn super_projection_elem(&mut self,
                 match *proj {
                     ProjectionElem::Deref => {
                     }
+                    ProjectionElem::Subslice { from: _, to: _ } => {
+                    }
                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
                         self.visit_ty(ty);
                     }
index aa885eb47424d8ade55971fa0bbe562ae3a77c15..155b615d83c7b704262e424fc49a652cafab8b27 100644 (file)
@@ -49,6 +49,8 @@ fn lift(&self) -> Self::Abstract {
                 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,
index 27d208240ac1cd2d8dc730585838f90ce8ef7bd7..1acee8e64a9af4ffd2b3aa28f160548157977389 100644 (file)
@@ -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);
-                        }
                     }
                 }
             }
index 49fa1896ff8dd68cd8b9fbc589d89e43509a421b..c3da2b9e53d828c3bd04e9fd54088050491213a8 100644 (file)
@@ -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)
index 6104679d6500f376f010f4503d6712d6e1f1745b..ffb13356ba2c248638f6bdd790d1c7a640694e0a 100644 (file)
@@ -429,42 +429,83 @@ fn join_otherwise_blocks(&mut self,
     /// 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,
index c707bb8a27b6f53983e7eececd0c78bfc93cbf0d..8392248e3f22e2088ffe6e99e4e38cb4f47bbcbd 100644 (file)
@@ -31,7 +31,7 @@
 
 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 @@ pub fn simplify_candidate<'pat>(&mut self,
             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 @@ pub fn simplify_candidate<'pat>(&mut self,
     /// 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 @@ fn simplify_match_pair<'pat>(&mut self,
                     candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
                 }
 
-                Ok(block)
+                Ok(())
             }
 
             PatternKind::Constant { .. } => {
@@ -96,37 +93,31 @@ fn simplify_match_pair<'pat>(&mut self,
             }
 
             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(())
             }
         }
     }
index 1f0c4bd9e0dd6e911ead8a22302a6f2bf46d893b..668bdcf735802499d84f5978476a43777b69e7b1 100644 (file)
@@ -24,6 +24,7 @@
 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 @@ pub fn sort_candidate<'pat>(&mut self,
             }
         };
 
-        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
@@ -544,6 +594,25 @@ fn candidate_without_match_pair<'pat>(&mut self,
         }
     }
 
+    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>,
index 2e9cc96c046817d2a4f4fbd6330f3cc243c21926..53ebf6fceb5c807e2f8ea006dad651db8f42dd46 100644 (file)
@@ -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 @@ pub fn field_match_pairs<'pat>(&mut self,
                    .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 @@ fn prefix_suffix<'pat>(&mut self,
                       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()
@@ -112,9 +73,7 @@ fn prefix_suffix<'pat>(&mut self,
                       let lvalue = lvalue.clone().elem(elem);
                       MatchPair::new(lvalue, subpattern)
                   })
-                  .collect();
-
-        match_pairs.extend(prefix_pairs.into_iter().chain(suffix_pairs));
+        );
     }
 }
 
index bce096deea131a423bb26ff3856db232e63d3be8..3fdf492611d467a2ade1e13dbcb8b27cb1d448b6 100644 (file)
@@ -509,6 +509,7 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
                         }
 
                         ProjectionElem::ConstantIndex {..} |
+                        ProjectionElem::Subslice {..} |
                         ProjectionElem::Downcast(..) => {
                             this.not_const()
                         }
@@ -708,7 +709,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
                 }
             }
 
-            Rvalue::Slice {..} |
             Rvalue::InlineAsm {..} => {
                 self.not_const();
             }
index 4bfa3b16efa16124400b319de13a9940eb69f7a9..c38f1f1e6c0fad98648c8fe70bb1b86d5f8da189 100644 (file)
@@ -203,6 +203,26 @@ fn sanitize_projection(&mut self,
                     })
                 }
             }
+            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 => {
index bc79482666c929c54ab7d7f2ef782b1ede917e6b..841dcf0301c3fe84bb452fda47159290c67fd861 100644 (file)
 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 @@ pub fn trans_lvalue(&mut self,
         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 @@ pub fn trans_lvalue(&mut self,
                         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 @@ pub fn trans_lvalue(&mut self,
                     }
                     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 @@ pub fn trans_lvalue(&mut self,
                         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 @@ pub fn trans_lvalue(&mut self,
                     ty: projected_ty,
                 }
             }
-        }
+        };
+        debug!("trans_lvalue(lvalue={:?}) => {:?}", lvalue, result);
+        result
     }
 
     // Perform an action using the given Lvalue.
index 6779498fe2c6ebd149ad58ca29d34d8367981a24..09b07c1440ec579b1ca3099d7d4790d8beaf1233 100644 (file)
@@ -29,7 +29,7 @@
 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 @@ 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);
@@ -498,7 +478,6 @@ pub fn trans_rvalue_operand(&mut self,
             }
             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,
     }
index 99b443e292491fed7164c2950f2ff1c1704a001f..2fbeb43b8a3a517df2770d60edf5757ab2fecf17 100644 (file)
@@ -19,8 +19,8 @@
 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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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
index fd1b60551734cffcb1bc576f418b02203a5c7469..a8cb21126c079c0ec6d45bfce2b7b36d9ec39639 100644 (file)
@@ -1157,25 +1157,13 @@ fn link_pattern<'t>(&self,
         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(()) => {}
-                        }
-                    }
                     _ => {}
                 }
             });
index 67a082ee52066ca703d2cee586ed41500696c9de..86717da24c54f03493a34cb4bf4417e15ab67222 100644 (file)
@@ -4139,5 +4139,8 @@ fn fly(&self) {} // And now that's ok!
            // 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 `{}`
 }
index 55e485e5811acc687dce80d57e2f43571489f3d3..5519230890cb6f84c95b0cb3353fce8cc3a1de33 100644 (file)
@@ -560,15 +560,20 @@ fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
         }
     }
 
+    // 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 @@ fn initial_trail_surrogate(&self) -> Option<u16> {
         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
         }
     }
 }
index 15771295743c16592dff72545d909f6e18b7198a..f595d9d81cc6ef6bcb64eb67ce9055834880443d 100644 (file)
@@ -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
                 }
                 _ => {
index 98052ad31a7ef13b524fba8b559d493bd834aabd..63e80b90ac81e6f211d885b77285f64ed6c142d6 100644 (file)
@@ -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
index db635893c81b9f5d4c03c61e1545dba44a5fba5f..9dfd4d779284329ff53909c372604d51869c7a10 100644 (file)
@@ -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
         }
         _ => {}
index 97dcaeb0bf1a3d2c2eb8a9b90f821aa0c72c81f5..fddb9838c44b5e945561561ea298d22fc339a6e4 100644 (file)
@@ -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]);
index eec6c8473eb3d167bce7d644e773dada2c1120be..d89b4100789f95d7132e969bef3e7e627fdbc8c0 100644 (file)
@@ -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
index 82b3490d7d7e118c79a875ec91288b0cd2960ad9..a849e4e2faf3b51ff5d6cc97d90121ca1fadae82 100644 (file)
@@ -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
index 1333bfac64ee86d1edc9f2d0b3c624ec70462a5a..978d6f59b2df455b41b91ecc45d7244c2f7f6e88 100644 (file)
@@ -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
     };
 }
index 1580ec00f94b068b3c59c0884975ed4a8885bad2..32a6ea4f062cbc9819392615e13cd579a288d13e 100644 (file)
 
 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
     }
 }
 
index fe03373a45d9fd6b08ab2488febec50aea53e3d5..6885c8d94c6b4fd16535103a91fa52bca135d372 100644 (file)
 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)
     };
 }
index 7ed7f5898b1b7411f4b49e713b8f2203db2eb5f5..82e82df31861ff35ab4a4fe913be379ebab96bda 100644 (file)
 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)
   };
 }
index ec29a84f44e4bd105019295b97c1bb15c69665c6..d0964d2aabea755357b9af916f00c127a642808d 100644 (file)
@@ -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);
     }
 }
index 2831499c73d8732e5dd676ca3360631524e4f145..375d855d1fd31e6edae51647b965f13dec2e370f 100644 (file)
@@ -13,9 +13,6 @@
 fn main() {
     match () {
         [()] => { }
-        //~^ ERROR mismatched types
-        //~| expected type `()`
-        //~| found type `&[_]`
-        //~| expected (), found &-ptr
+        //~^ ERROR expected an array or slice, found `()`
     }
 }
index ef75213d34b85109fa53a7e76d873d9b063f007d..3ac4958e7db0f6425b5a5d170574d967e1849bdf 100644 (file)
 
 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
+    };
 }
index 48b70b4bda08efc31983e0bffaee437639cb5ae3..57e3a58b5660e27267d66d9af9f9643d6dd2542b 100644 (file)
@@ -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
         _ => {}
     }
index ad2b8c400e57608c0e2613223c846e1d3ae590f8..1d524217a12a29519653256f9a8785e64d334dbf 100644 (file)
@@ -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)"
     }
 }
 
index b9749c2696e32adf505b7df91a53df19dba6bafd..017baacc9d329b771f7e40f295acbbfafeb03a24 100644 (file)
@@ -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] => {}
         [] => {}
index b986878f78396ae823bf9e3fac40e93486dd65f2..0b12a9acbcb9e9d56de662b81d4234bda7fc35a7 100644 (file)
@@ -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.., _] => ()
     }
 }
 
index 7b00ea4a520cddb5f3be7c429073c855af69004b..cee0caeb465f56d3206266d85cc4f6f769730fb3 100644 (file)
@@ -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
             }
index b55754ee59b35c11e68f316a4fb7e0e2a1988b30..508360cb70110a96ac10973133548c07053a1afc 100644 (file)
@@ -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)
     }
 }
index 384bd9df7cfedadb9bf042907d7a7b693bab97eb..e596bee8bfe9fc7afc4936c33c7537873306aabb 100644 (file)
@@ -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);
index badc013cd621f6297af82991af69264dc35b0073..0008825226ba0161fdcd88b4c92e457c42331ec6 100644 (file)
@@ -11,6 +11,7 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
+#![feature(rustc_attrs)]
 
 use std::ops::Add;
 
@@ -21,6 +22,7 @@
     [a, b, b, a]
 }
 
+#[rustc_mir]
 fn main() {
     assert_eq!(foo([1, 2, 3]), (1, 3, 6));
 
index 43e0b442251bd112e948324a2a7b68ba8d3f570e..010c1455210084b521a898b125e183d8d1f2f1cb 100644 (file)
 
 #![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"
     }
 }
index ee70ea58750d9d5bd0560d3e1bf8868fb313680c..7a6129d311ee386e83a51ca4fb706ac2fa0809b5 100644 (file)
 
 #![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
+        }
     }
 }
 
index e7553c8e157e3ce3ba99771069d8d0fac65a472c..1093bc7c18b867e6f6e817e32527df9e09d6b52d 100644 (file)
@@ -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);
index eedf27f85770044a2867fe853eaa5cabb286b134..075709a63b5f5d2978947ea1062e189fc7440a6a 100644 (file)
@@ -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();
index 6cc7e3a072cf040d4dc60f574d17d66764295c96..6084a0d07a114911f2e180062d159f3e42f11f6c 100644 (file)
 
 
 #![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 }] => {
index 697508ae4888916085dc2067a8e0cf309b4e7453..00f4aa98a3e062bf2694beca39bb2882f682f2d6 100644 (file)
@@ -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 ())
     }
 }