about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcollections/vec.rs80
-rw-r--r--src/libcore/ops.rs105
-rw-r--r--src/libcore/slice.rs58
-rw-r--r--src/librustc/middle/cfg/construct.rs7
-rw-r--r--src/librustc/middle/expr_use_visitor.rs21
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/liveness.rs10
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/trans/callee.rs24
-rw-r--r--src/librustc/middle/trans/debuginfo.rs6
-rw-r--r--src/librustc/middle/trans/expr.rs40
-rw-r--r--src/librustc/middle/ty.rs6
-rw-r--r--src/librustc/middle/typeck/check/mod.rs267
-rw-r--r--src/librustc_back/svh.rs2
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/parser.rs105
-rw-r--r--src/libsyntax/print/pprust.rs24
-rw-r--r--src/libsyntax/visit.rs5
-rw-r--r--src/test/compile-fail/slice-1.rs19
-rw-r--r--src/test/compile-fail/slice-2.rs25
-rw-r--r--src/test/compile-fail/slice-borrow.rs19
-rw-r--r--src/test/compile-fail/slice-mut-2.rs17
-rw-r--r--src/test/compile-fail/slice-mut.rs22
-rw-r--r--src/test/run-pass/match-range-static.rs2
-rw-r--r--src/test/run-pass/slice-2.rs69
-rw-r--r--src/test/run-pass/slice.rs70
27 files changed, 909 insertions, 105 deletions
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index f570573262a..4051f682134 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -20,6 +20,7 @@ use core::default::Default;
 use core::fmt;
 use core::mem;
 use core::num;
+use core::ops;
 use core::ptr;
 use core::raw::Slice as RawSlice;
 use core::uint;
@@ -464,6 +465,47 @@ impl<T> Index<uint,T> for Vec<T> {
     }
 }*/
 
+impl<T> ops::Slice<uint, [T]> for Vec<T> {
+    #[inline]
+    fn as_slice_<'a>(&'a self) -> &'a [T] {
+        self.as_slice()
+    }
+
+    #[inline]
+    fn slice_from_<'a>(&'a self, start: &uint) -> &'a [T] {
+        self.as_slice().slice_from_(start)
+    }
+
+    #[inline]
+    fn slice_to_<'a>(&'a self, end: &uint) -> &'a [T] {
+        self.as_slice().slice_to_(end)
+    }
+    #[inline]
+    fn slice_<'a>(&'a self, start: &uint, end: &uint) -> &'a [T] {
+        self.as_slice().slice_(start, end)
+    }
+}
+
+impl<T> ops::SliceMut<uint, [T]> for Vec<T> {
+    #[inline]
+    fn as_mut_slice_<'a>(&'a mut self) -> &'a mut [T] {
+        self.as_mut_slice()
+    }
+
+    #[inline]
+    fn slice_from_mut_<'a>(&'a mut self, start: &uint) -> &'a mut [T] {
+        self.as_mut_slice().slice_from_mut_(start)
+    }
+
+    #[inline]
+    fn slice_to_mut_<'a>(&'a mut self, end: &uint) -> &'a mut [T] {
+        self.as_mut_slice().slice_to_mut_(end)
+    }
+    #[inline]
+    fn slice_mut_<'a>(&'a mut self, start: &uint, end: &uint) -> &'a mut [T] {
+        self.as_mut_slice().slice_mut_(start, end)
+    }
+}
 impl<T> FromIterator<T> for Vec<T> {
     #[inline]
     fn from_iter<I:Iterator<T>>(mut iterator: I) -> Vec<T> {
@@ -2327,6 +2369,44 @@ mod tests {
         let _ = vec[3];
     }
 
+    // NOTE uncomment after snapshot
+    /*
+    #[test]
+    #[should_fail]
+    fn test_slice_out_of_bounds_1() {
+        let x: Vec<int> = vec![1, 2, 3, 4, 5];
+        x[-1..];
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_slice_out_of_bounds_2() {
+        let x: Vec<int> = vec![1, 2, 3, 4, 5];
+        x[..6];
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_slice_out_of_bounds_3() {
+        let x: Vec<int> = vec![1, 2, 3, 4, 5];
+        x[-1..4];
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_slice_out_of_bounds_4() {
+        let x: Vec<int> = vec![1, 2, 3, 4, 5];
+        x[1..6];
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_slice_out_of_bounds_5() {
+        let x: Vec<int> = vec![1, 2, 3, 4, 5];
+        x[3..2];
+    }
+    */
+
     #[test]
     fn test_swap_remove_empty() {
         let mut vec: Vec<uint> = vec!();
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 94febf03635..718d3119995 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -638,7 +638,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
  * ```
  */
 #[lang="index"]
-pub trait Index<Index,Result> {
+pub trait Index<Index, Result> {
     /// The method for the indexing (`Foo[Bar]`) operation
     fn index<'a>(&'a self, index: &Index) -> &'a Result;
 }
@@ -651,7 +651,7 @@ pub trait Index<Index,Result> {
  * # Example
  *
  * A trivial implementation of `IndexMut`. When `Foo[Foo]` happens, it ends up
- * calling `index`, and therefore, `main` prints `Indexing!`.
+ * calling `index_mut`, and therefore, `main` prints `Indexing!`.
  *
  * ```
  * struct Foo;
@@ -669,13 +669,112 @@ pub trait Index<Index,Result> {
  * ```
  */
 #[lang="index_mut"]
-pub trait IndexMut<Index,Result> {
+pub trait IndexMut<Index, Result> {
     /// The method for the indexing (`Foo[Bar]`) operation
     fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result;
 }
 
 /**
  *
+ * The `Slice` trait is used to specify the functionality of slicing operations
+ * like `arr[from..to]` when used in an immutable context.
+ *
+ * # Example
+ *
+ * A trivial implementation of `Slice`. When `Foo[..Foo]` happens, it ends up
+ * calling `slice_to`, and therefore, `main` prints `Slicing!`.
+ *
+ * ```
+ * struct Foo;
+ *
+ * impl ::core::ops::Slice<Foo, Foo> for Foo {
+ *     fn as_slice_<'a>(&'a self) -> &'a Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_from_<'a>(&'a self, from: &Foo) -> &'a Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_to_<'a>(&'a self, to: &Foo) -> &'a Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_<'a>(&'a self, from: &Foo, to: &Foo) -> &'a Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ * }
+ *
+ * fn main() {
+ *     Foo[..Foo];
+ * }
+ * ```
+ */
+// FIXME(#17273) remove the postscript _s
+#[lang="slice"]
+pub trait Slice<Idx, Sized? Result> for Sized? {
+    /// The method for the slicing operation foo[]
+    fn as_slice_<'a>(&'a self) -> &'a Result;
+    /// The method for the slicing operation foo[from..]
+    fn slice_from_<'a>(&'a self, from: &Idx) -> &'a Result;
+    /// The method for the slicing operation foo[..to]
+    fn slice_to_<'a>(&'a self, to: &Idx) -> &'a Result;
+    /// The method for the slicing operation foo[from..to]
+    fn slice_<'a>(&'a self, from: &Idx, to: &Idx) -> &'a Result;
+}
+
+/**
+ *
+ * The `SliceMut` trait is used to specify the functionality of slicing
+ * operations like `arr[from..to]`, when used in a mutable context.
+ *
+ * # Example
+ *
+ * A trivial implementation of `SliceMut`. When `Foo[Foo..]` happens, it ends up
+ * calling `slice_from_mut`, and therefore, `main` prints `Slicing!`.
+ *
+ * ```
+ * struct Foo;
+ *
+ * impl ::core::ops::SliceMut<Foo, Foo> for Foo {
+ *     fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_from_mut_<'a>(&'a mut self, from: &Foo) -> &'a mut Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_to_mut_<'a>(&'a mut self, to: &Foo) -> &'a mut Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ *     fn slice_mut_<'a>(&'a mut self, from: &Foo, to: &Foo) -> &'a mut Foo {
+ *         println!("Slicing!");
+ *         self
+ *     }
+ * }
+ *
+ * fn main() {
+ *     Foo[mut Foo..];
+ * }
+ * ```
+ */
+// FIXME(#17273) remove the postscript _s
+#[lang="slice_mut"]
+pub trait SliceMut<Idx, Sized? Result> for Sized? {
+    /// The method for the slicing operation foo[]
+    fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Result;
+    /// The method for the slicing operation foo[from..]
+    fn slice_from_mut_<'a>(&'a mut self, from: &Idx) -> &'a mut Result;
+    /// The method for the slicing operation foo[..to]
+    fn slice_to_mut_<'a>(&'a mut self, to: &Idx) -> &'a mut Result;
+    /// The method for the slicing operation foo[from..to]
+    fn slice_mut_<'a>(&'a mut self, from: &Idx, to: &Idx) -> &'a mut Result;
+}
+/**
+ *
  * The `Deref` trait is used to specify the functionality of dereferencing
  * operations like `*v`.
  *
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 65ad7bb1753..5368cb44502 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -42,6 +42,7 @@ use cmp;
 use default::Default;
 use iter::*;
 use num::{CheckedAdd, Saturating, div_rem};
+use ops;
 use option::{None, Option, Some};
 use ptr;
 use ptr::RawPtr;
@@ -475,6 +476,63 @@ impl<'a,T> ImmutableSlice<'a, T> for &'a [T] {
     }
 }
 
+impl<T> ops::Slice<uint, [T]> for [T] {
+    #[inline]
+    fn as_slice_<'a>(&'a self) -> &'a [T] {
+        self
+    }
+
+    #[inline]
+    fn slice_from_<'a>(&'a self, start: &uint) -> &'a [T] {
+        self.slice_(start, &self.len())
+    }
+
+    #[inline]
+    fn slice_to_<'a>(&'a self, end: &uint) -> &'a [T] {
+        self.slice_(&0, end)
+    }
+    #[inline]
+    fn slice_<'a>(&'a self, start: &uint, end: &uint) -> &'a [T] {
+        assert!(*start <= *end);
+        assert!(*end <= self.len());
+        unsafe {
+            transmute(RawSlice {
+                    data: self.as_ptr().offset(*start as int),
+                    len: (*end - *start)
+                })
+        }
+    }
+}
+
+impl<T> ops::SliceMut<uint, [T]> for [T] {
+    #[inline]
+    fn as_mut_slice_<'a>(&'a mut self) -> &'a mut [T] {
+        self
+    }
+
+    #[inline]
+    fn slice_from_mut_<'a>(&'a mut self, start: &uint) -> &'a mut [T] {
+        let len = &self.len();
+        self.slice_mut_(start, len)
+    }
+
+    #[inline]
+    fn slice_to_mut_<'a>(&'a mut self, end: &uint) -> &'a mut [T] {
+        self.slice_mut_(&0, end)
+    }
+    #[inline]
+    fn slice_mut_<'a>(&'a mut self, start: &uint, end: &uint) -> &'a mut [T] {
+        assert!(*start <= *end);
+        assert!(*end <= self.len());
+        unsafe {
+            transmute(RawSlice {
+                    data: self.as_ptr().offset(*start as int),
+                    len: (*end - *start)
+                })
+        }
+    }
+}
+
 /// Extension methods for vectors such that their elements are
 /// mutable.
 #[experimental = "may merge with other traits; may lose region param; needs review"]
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index f1c288ae7a9..b268c2a7a51 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -424,6 +424,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.call(expr, pred, &**l, Some(&**r).into_iter())
             }
 
+            ast::ExprSlice(ref base, ref start, ref end, _) => {
+                self.call(expr,
+                          pred,
+                          &**base,
+                          start.iter().chain(end.iter()).map(|x| &**x))
+            }
+
             ast::ExprUnary(_, ref e) if self.is_method_call(expr) => {
                 self.call(expr, pred, &**e, None::<ast::Expr>.iter())
             }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index c8c5284022d..7ae01c30e5c 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -316,7 +316,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
             ast::ExprPath(..) => { }
 
             ast::ExprUnary(ast::UnDeref, ref base) => {      // *base
-                if !self.walk_overloaded_operator(expr, &**base, None) {
+                if !self.walk_overloaded_operator(expr, &**base, Vec::new()) {
                     self.select_from_expr(&**base);
                 }
             }
@@ -330,12 +330,23 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
             }
 
             ast::ExprIndex(ref lhs, ref rhs) => {       // lhs[rhs]
-                if !self.walk_overloaded_operator(expr, &**lhs, Some(&**rhs)) {
+                if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) {
                     self.select_from_expr(&**lhs);
                     self.consume_expr(&**rhs);
                 }
             }
 
+            ast::ExprSlice(ref base, ref start, ref end, _) => {    // base[start..end]
+                let args = match (start, end) {
+                    (&Some(ref e1), &Some(ref e2)) => vec![&**e1, &**e2],
+                    (&Some(ref e), &None) => vec![&**e],
+                    (&None, &Some(ref e)) => vec![&**e],
+                    (&None, &None) => Vec::new()
+                };
+                let overloaded = self.walk_overloaded_operator(expr, &**base, args);
+                assert!(overloaded);
+            }
+
             ast::ExprCall(ref callee, ref args) => {    // callee(args)
                 self.walk_callee(expr, &**callee);
                 self.consume_exprs(args);
@@ -430,13 +441,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
             }
 
             ast::ExprUnary(_, ref lhs) => {
-                if !self.walk_overloaded_operator(expr, &**lhs, None) {
+                if !self.walk_overloaded_operator(expr, &**lhs, Vec::new()) {
                     self.consume_expr(&**lhs);
                 }
             }
 
             ast::ExprBinary(_, ref lhs, ref rhs) => {
-                if !self.walk_overloaded_operator(expr, &**lhs, Some(&**rhs)) {
+                if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) {
                     self.consume_expr(&**lhs);
                     self.consume_expr(&**rhs);
                 }
@@ -774,7 +785,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
     fn walk_overloaded_operator(&mut self,
                                 expr: &ast::Expr,
                                 receiver: &ast::Expr,
-                                rhs: Option<&ast::Expr>)
+                                rhs: Vec<&ast::Expr>)
                                 -> bool
     {
         if !self.typer.is_method_call(expr.id) {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 1875c53f074..daba3b701c0 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -247,6 +247,8 @@ lets_do_this! {
     ShrTraitLangItem,                "shr",                     shr_trait;
     IndexTraitLangItem,              "index",                   index_trait;
     IndexMutTraitLangItem,           "index_mut",               index_mut_trait;
+    SliceTraitLangItem,              "slice",                   slice_trait;
+    SliceMutTraitLangItem,           "slice_mut",               slice_mut_trait;
 
     UnsafeTypeLangItem,              "unsafe",                  unsafe_type;
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index fee6c77a799..69d37edf5ab 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
 
       // otherwise, live nodes are not required:
       ExprIndex(..) | ExprField(..) | ExprTupField(..) | ExprVec(..) |
-      ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
+      ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprSlice(..) |
       ExprBinary(..) | ExprAddrOf(..) |
       ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
       ExprAgain(_) | ExprLit(_) | ExprRet(..) | ExprBlock(..) |
@@ -1184,6 +1184,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_expr(&**l, r_succ)
           }
 
+          ExprSlice(ref e1, ref e2, ref e3, _) => {
+            let succ = e3.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ));
+            let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ));
+            self.propagate_through_expr(&**e1, succ)
+          }
+
           ExprAddrOf(_, ref e) |
           ExprCast(ref e, _) |
           ExprUnary(_, ref e) |
@@ -1468,7 +1474,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
       ExprTupField(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) |
       ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
-      ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
+      ExprAgain(..) | ExprLit(_) | ExprBlock(..) | ExprSlice(..) |
       ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
       ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
       ExprPath(..) | ExprBox(..) => {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 17d941b5958..04883d94872 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -504,7 +504,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           ast::ExprAssign(..) | ast::ExprAssignOp(..) |
           ast::ExprFnBlock(..) | ast::ExprProc(..) |
           ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
-          ast::ExprUnary(..) |
+          ast::ExprUnary(..) | ast::ExprSlice(..) |
           ast::ExprMethodCall(..) | ast::ExprCast(..) |
           ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
           ast::ExprBinary(..) | ast::ExprWhile(..) |
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index c54a446c455..9d30cd77717 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -860,10 +860,10 @@ pub enum CallArgs<'a> {
     // value.
     ArgVals(&'a [ValueRef]),
 
-    // For overloaded operators: `(lhs, Option(rhs, rhs_id))`. `lhs`
+    // For overloaded operators: `(lhs, Vec(rhs, rhs_id))`. `lhs`
     // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
-    // the right-hand-side (if any).
-    ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
+    // the right-hand-side arguments (if any).
+    ArgOverloadedOp(Datum<Expr>, Vec<(Datum<Expr>, ast::NodeId)>),
 
     // Supply value of arguments as a list of expressions that must be
     // translated, for overloaded call operators.
@@ -1047,17 +1047,13 @@ pub fn trans_args<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                 DontAutorefArg)
             }));
 
-            match rhs {
-                Some((rhs, rhs_id)) => {
-                    assert_eq!(arg_tys.len(), 2);
-
-                    llargs.push(unpack_result!(bcx, {
-                        trans_arg_datum(bcx, *arg_tys.get(1), rhs,
-                                        arg_cleanup_scope,
-                                        DoAutorefArg(rhs_id))
-                    }));
-                }
-                None => assert_eq!(arg_tys.len(), 1)
+            assert_eq!(arg_tys.len(), 1 + rhs.len());
+            for (rhs, rhs_id) in rhs.move_iter() {
+                llargs.push(unpack_result!(bcx, {
+                    trans_arg_datum(bcx, *arg_tys.get(1), rhs,
+                                    arg_cleanup_scope,
+                                    DoAutorefArg(rhs_id))
+                }));
             }
         }
         ArgVals(vs) => {
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 62571ef9f9b..ac4b7d2e6f1 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -3479,6 +3479,12 @@ fn populate_scope_map(cx: &CrateContext,
                 walk_expr(cx, &**rhs, scope_stack, scope_map);
             }
 
+            ast::ExprSlice(ref base, ref start, ref end, _) => {
+                walk_expr(cx, &**base, scope_stack, scope_map);
+                start.as_ref().map(|x| walk_expr(cx, &**x, scope_stack, scope_map));
+                end.as_ref().map(|x| walk_expr(cx, &**x, scope_stack, scope_map));
+            }
+
             ast::ExprVec(ref init_expressions) |
             ast::ExprTup(ref init_expressions) => {
                 for ie in init_expressions.iter() {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 77712570185..6876403c8c2 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -590,6 +590,34 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprIndex(ref base, ref idx) => {
             trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
         }
+        ast::ExprSlice(ref base, ref start, ref end, _) => {
+            let _icx = push_ctxt("trans_slice");
+            let ccx = bcx.ccx();
+
+            let method_call = MethodCall::expr(expr.id);
+            let method_ty = ccx.tcx()
+                               .method_map
+                               .borrow()
+                               .find(&method_call)
+                               .map(|method| method.ty);
+            let base_datum = unpack_datum!(bcx, trans(bcx, &**base));
+
+            let mut args = vec![];
+            start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
+            end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
+
+            let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty.unwrap()));
+            let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice");
+
+            unpack_result!(bcx,
+                           trans_overloaded_op(bcx,
+                                               expr,
+                                               method_call,
+                                               base_datum,
+                                               args,
+                                               Some(SaveIn(scratch.val))));
+            DatumBlock::new(bcx, scratch.to_expr_datum())
+        }
         ast::ExprBox(_, ref contents) => {
             // Special case for `Box<T>` and `Gc<T>`
             let box_ty = expr_ty(bcx, expr);
@@ -725,7 +753,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                    index_expr,
                                                    method_call,
                                                    base_datum,
-                                                   Some((ix_datum, idx.id)),
+                                                   vec![(ix_datum, idx.id)],
                                                    None));
             let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
             let elt_ty = match ty::deref(ref_ty, true) {
@@ -1044,20 +1072,20 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
             let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
-                                Some((rhs_datum, rhs.id)), Some(dest)).bcx
+                                vec![(rhs_datum, rhs.id)], Some(dest)).bcx
         }
         ast::ExprUnary(_, ref subexpr) => {
             // if not overloaded, would be RvalueDatumExpr
             let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
-                                arg, None, Some(dest)).bcx
+                                arg, Vec::new(), Some(dest)).bcx
         }
         ast::ExprIndex(ref base, ref idx) => {
             // if not overloaded, would be RvalueDatumExpr
             let base = unpack_datum!(bcx, trans(bcx, &**base));
             let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
             trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
-                                Some((idx_datum, idx.id)), Some(dest)).bcx
+                                vec![(idx_datum, idx.id)], Some(dest)).bcx
         }
         ast::ExprCast(ref val, _) => {
             // DPS output mode means this is a trait cast:
@@ -1751,7 +1779,7 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    expr: &ast::Expr,
                                    method_call: MethodCall,
                                    lhs: Datum<Expr>,
-                                   rhs: Option<(Datum<Expr>, ast::NodeId)>,
+                                   rhs: Vec<(Datum<Expr>, ast::NodeId)>,
                                    dest: Option<Dest>)
                                    -> Result<'blk, 'tcx> {
     let method_ty = bcx.tcx().method_map.borrow().get(&method_call).ty;
@@ -2074,7 +2102,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
             unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
-                                                    datum, None, Some(SaveIn(scratch.val))));
+                                                    datum, Vec::new(), Some(SaveIn(scratch.val))));
             scratch.to_expr_datum()
         }
         None => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 897bc4517f4..d6a36cd7e38 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3648,6 +3648,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
             // the index method invoked for `a[i]` always yields an `&T`
             ast::ExprIndex(..) => LvalueExpr,
 
+            // the slice method invoked for `a[..]` always yields an `&T`
+            ast::ExprSlice(..) => LvalueExpr,
+
             // `for` loops are statements
             ast::ExprForLoop(..) => RvalueStmtExpr,
 
@@ -3702,7 +3705,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
         ast::ExprUnary(ast::UnDeref, _) |
         ast::ExprField(..) |
         ast::ExprTupField(..) |
-        ast::ExprIndex(..) => {
+        ast::ExprIndex(..) |
+        ast::ExprSlice(..) => {
             LvalueExpr
         }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index c8728d375f6..3257ddd11cd 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -110,7 +110,7 @@ use middle::typeck::rscope::RegionScope;
 use middle::typeck::{lookup_def_ccx};
 use middle::typeck::no_params;
 use middle::typeck::{require_same_types};
-use middle::typeck::{MethodCall, MethodMap, ObjectCastMap};
+use middle::typeck::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
 use middle::typeck::{TypeAndSubsts};
 use middle::typeck;
 use middle::lang_items::TypeIdLangItem;
@@ -124,7 +124,6 @@ use std::cell::{Cell, RefCell};
 use std::collections::HashMap;
 use std::mem::replace;
 use std::rc::Rc;
-use std::slice;
 use syntax::abi;
 use syntax::ast::{ProvidedMethod, RequiredMethod, TypeTraitItem};
 use syntax::ast;
@@ -2188,12 +2187,12 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
 }
 
 /// Attempts to resolve a call expression as an overloaded call.
-fn try_overloaded_call(fcx: &FnCtxt,
-                       call_expression: &ast::Expr,
-                       callee: &ast::Expr,
-                       callee_type: ty::t,
-                       args: &[P<ast::Expr>])
-                       -> bool {
+fn try_overloaded_call<'a>(fcx: &FnCtxt,
+                           call_expression: &ast::Expr,
+                           callee: &ast::Expr,
+                           callee_type: ty::t,
+                           args: &[&'a P<ast::Expr>])
+                           -> bool {
     // Bail out if the callee is a bare function or a closure. We check those
     // manually.
     match *structure_of(fcx, callee.span, callee_type) {
@@ -2276,18 +2275,125 @@ fn try_overloaded_deref(fcx: &FnCtxt,
         (method, _) => method
     };
 
+    make_return_type(fcx, method_call, method)
+}
+
+fn get_method_ty(method: &Option<MethodCallee>) -> ty::t {
+    match method {
+        &Some(ref method) => method.ty,
+        &None => ty::mk_err()
+    }
+}
+
+fn make_return_type(fcx: &FnCtxt,
+                    method_call: Option<MethodCall>,
+                    method: Option<MethodCallee>)
+                    -> Option<ty::mt> {
     match method {
         Some(method) => {
             let ref_ty = ty::ty_fn_ret(method.ty);
             match method_call {
                 Some(method_call) => {
-                    fcx.inh.method_map.borrow_mut().insert(method_call, method);
+                    fcx.inh.method_map.borrow_mut().insert(method_call,
+                                                           method);
                 }
                 None => {}
             }
             ty::deref(ref_ty, true)
         }
-        None => None
+        None => None,
+    }
+}
+
+fn try_overloaded_slice(fcx: &FnCtxt,
+                        method_call: Option<MethodCall>,
+                        expr: &ast::Expr,
+                        base_expr: &ast::Expr,
+                        base_ty: ty::t,
+                        start_expr: &Option<P<ast::Expr>>,
+                        end_expr: &Option<P<ast::Expr>>,
+                        mutbl: &ast::Mutability)
+                        -> Option<ty::mt> {
+    let method = if mutbl == &ast::MutMutable {
+        // Try `SliceMut` first, if preferred.
+        match fcx.tcx().lang_items.slice_mut_trait() {
+            Some(trait_did) => {
+                let method_name = match (start_expr, end_expr) {
+                    (&Some(_), &Some(_)) => "slice_mut_",
+                    (&Some(_), &None) => "slice_from_mut_",
+                    (&None, &Some(_)) => "slice_to_mut_",
+                    (&None, &None) => "as_mut_slice_",
+                };
+
+                method::lookup_in_trait(fcx,
+                                        expr.span,
+                                        Some(&*base_expr),
+                                        token::intern(method_name),
+                                        trait_did,
+                                        base_ty,
+                                        [],
+                                        DontAutoderefReceiver,
+                                        IgnoreStaticMethods)
+            }
+            _ => None,
+        }
+    } else {
+        // Otherwise, fall back to `Slice`.
+        // FIXME(#17293) this will not coerce base_expr, so we miss the Slice
+        // trait for `&mut [T]`.
+        match fcx.tcx().lang_items.slice_trait() {
+            Some(trait_did) => {
+                let method_name = match (start_expr, end_expr) {
+                    (&Some(_), &Some(_)) => "slice_",
+                    (&Some(_), &None) => "slice_from_",
+                    (&None, &Some(_)) => "slice_to_",
+                    (&None, &None) => "as_slice_",
+                };
+
+                method::lookup_in_trait(fcx,
+                                        expr.span,
+                                        Some(&*base_expr),
+                                        token::intern(method_name),
+                                        trait_did,
+                                        base_ty,
+                                        [],
+                                        DontAutoderefReceiver,
+                                        IgnoreStaticMethods)
+            }
+            _ => None,
+        }
+    };
+
+
+    // Regardless of whether the lookup succeeds, check the method arguments
+    // so that we have *some* type for each argument.
+    let method_type = get_method_ty(&method);
+
+    let mut args = vec![];
+    start_expr.as_ref().map(|x| args.push(x));
+    end_expr.as_ref().map(|x| args.push(x));
+
+    check_method_argument_types(fcx,
+                                expr.span,
+                                method_type,
+                                expr,
+                                args.as_slice(),
+                                DoDerefArgs,
+                                DontTupleArguments);
+
+    match method {
+        Some(method) => {
+            let result_ty = ty::ty_fn_ret(method.ty);
+            match method_call {
+                Some(method_call) => {
+                    fcx.inh.method_map.borrow_mut().insert(method_call,
+                                                           method);
+                }
+                None => {}
+            }
+            Some(ty::mt { ty: result_ty, mutbl: ast::MutImmutable })
+        }
+        None => None,
     }
 }
 
@@ -2333,32 +2439,16 @@ fn try_overloaded_index(fcx: &FnCtxt,
 
     // Regardless of whether the lookup succeeds, check the method arguments
     // so that we have *some* type for each argument.
-    let method_type = match method {
-        Some(ref method) => method.ty,
-        None => ty::mk_err()
-    };
+    let method_type = get_method_ty(&method);
     check_method_argument_types(fcx,
                                 expr.span,
                                 method_type,
                                 expr,
-                                slice::ref_slice(index_expr),
+                                &[index_expr],
                                 DoDerefArgs,
                                 DontTupleArguments);
 
-    match method {
-        Some(method) => {
-            let ref_ty = ty::ty_fn_ret(method.ty);
-            match method_call {
-                Some(method_call) => {
-                    fcx.inh.method_map.borrow_mut().insert(method_call,
-                                                           method);
-                }
-                None => {}
-            }
-            ty::deref(ref_ty, true)
-        }
-        None => None,
-    }
+    make_return_type(fcx, method_call, method)
 }
 
 /// Given the head of a `for` expression, looks up the `next` method in the
@@ -2442,14 +2532,14 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
     }
 }
 
-fn check_method_argument_types(fcx: &FnCtxt,
-                               sp: Span,
-                               method_fn_ty: ty::t,
-                               callee_expr: &ast::Expr,
-                               args_no_rcvr: &[P<ast::Expr>],
-                               deref_args: DerefArgs,
-                               tuple_arguments: TupleArgumentsFlag)
-                               -> ty::t {
+fn check_method_argument_types<'a>(fcx: &FnCtxt,
+                                   sp: Span,
+                                   method_fn_ty: ty::t,
+                                   callee_expr: &ast::Expr,
+                                   args_no_rcvr: &[&'a P<ast::Expr>],
+                                   deref_args: DerefArgs,
+                                   tuple_arguments: TupleArgumentsFlag)
+                                   -> ty::t {
     if ty::type_is_error(method_fn_ty) {
        let err_inputs = err_args(args_no_rcvr.len());
         check_argument_types(fcx,
@@ -2483,14 +2573,14 @@ fn check_method_argument_types(fcx: &FnCtxt,
     }
 }
 
-fn check_argument_types(fcx: &FnCtxt,
-                        sp: Span,
-                        fn_inputs: &[ty::t],
-                        _callee_expr: &ast::Expr,
-                        args: &[P<ast::Expr>],
-                        deref_args: DerefArgs,
-                        variadic: bool,
-                        tuple_arguments: TupleArgumentsFlag) {
+fn check_argument_types<'a>(fcx: &FnCtxt,
+                            sp: Span,
+                            fn_inputs: &[ty::t],
+                            _callee_expr: &ast::Expr,
+                            args: &[&'a P<ast::Expr>],
+                            deref_args: DerefArgs,
+                            variadic: bool,
+                            tuple_arguments: TupleArgumentsFlag) {
     /*!
      *
      * Generic function that factors out common logic from
@@ -2627,7 +2717,7 @@ fn check_argument_types(fcx: &FnCtxt,
                     DontDerefArgs => {}
                 }
 
-                check_expr_coercable_to_type(fcx, &**arg, formal_ty);
+                check_expr_coercable_to_type(fcx, &***arg, formal_ty);
             }
         }
     }
@@ -2636,12 +2726,12 @@ fn check_argument_types(fcx: &FnCtxt,
     // arguments which we skipped above.
     if variadic {
         for arg in args.iter().skip(expected_arg_count) {
-            check_expr(fcx, &**arg);
+            check_expr(fcx, &***arg);
 
             // There are a few types which get autopromoted when passed via varargs
             // in C but we just error out instead and require explicit casts.
             let arg_ty = structurally_resolved_type(fcx, arg.span,
-                                                    fcx.expr_ty(&**arg));
+                                                    fcx.expr_ty(&***arg));
             match ty::get(arg_ty).sty {
                 ty::ty_float(ast::TyF32) => {
                     fcx.type_error_message(arg.span,
@@ -2877,10 +2967,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
            expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
 
     // A generic function for doing all of the checking for call expressions
-    fn check_call(fcx: &FnCtxt,
-                  call_expr: &ast::Expr,
-                  f: &ast::Expr,
-                  args: &[P<ast::Expr>]) {
+    fn check_call<'a>(fcx: &FnCtxt,
+                      call_expr: &ast::Expr,
+                      f: &ast::Expr,
+                      args: &[&'a P<ast::Expr>]) {
         // Store the type of `f` as the type of the callee
         let fn_ty = fcx.expr_ty(f);
 
@@ -2990,11 +3080,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
         };
 
         // Call the generic checker.
+        let args: Vec<_> = args.slice_from(1).iter().map(|x| x).collect();
         let ret_ty = check_method_argument_types(fcx,
                                                  method_name.span,
                                                  fn_ty,
                                                  expr,
-                                                 args.slice_from(1),
+                                                 args.as_slice(),
                                                  DontDerefArgs,
                                                  DontTupleArguments);
 
@@ -3085,12 +3176,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             None => None
         };
         let args = match rhs {
-            Some(rhs) => slice::ref_slice(rhs),
-            None => {
-                // Work around the lack of coercion.
-                let empty: &[_] = &[];
-                empty
-            }
+            Some(rhs) => vec![rhs],
+            None => vec![]
         };
         match method {
             Some(method) => {
@@ -3102,7 +3189,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                             op_ex.span,
                                             method_ty,
                                             op_ex,
-                                            args,
+                                            args.as_slice(),
                                             DoDerefArgs,
                                             DontTupleArguments)
             }
@@ -3115,7 +3202,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                             op_ex.span,
                                             expected_ty,
                                             op_ex,
-                                            args,
+                                            args.as_slice(),
                                             DoDerefArgs,
                                             DontTupleArguments);
                 ty::mk_err()
@@ -4136,12 +4223,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
           check_expr(fcx, &**f);
           let f_ty = fcx.expr_ty(&**f);
 
+          let args: Vec<_> = args.iter().map(|x| x).collect();
           if !try_overloaded_call(fcx, expr, &**f, f_ty, args.as_slice()) {
               check_call(fcx, expr, &**f, args.as_slice());
               let (args_bot, args_err) = args.iter().fold((false, false),
                  |(rest_bot, rest_err), a| {
                      // is this not working?
-                     let a_ty = fcx.expr_ty(&**a);
+                     let a_ty = fcx.expr_ty(&***a);
                      (rest_bot || ty::type_is_bot(a_ty),
                       rest_err || ty::type_is_error(a_ty))});
               if ty::type_is_error(f_ty) || args_err {
@@ -4427,6 +4515,61 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
               }
           }
        }
+       ast::ExprSlice(ref base, ref start, ref end, ref mutbl) => {
+          check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
+          let raw_base_t = fcx.expr_ty(&**base);
+
+          let mut some_err = false;
+          if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
+              fcx.write_ty(id, raw_base_t);
+              some_err = true;
+          }
+
+          {
+              let check_slice_idx = |e: &ast::Expr| {
+                  check_expr(fcx, e);
+                  let e_t = fcx.expr_ty(e);
+                  if ty::type_is_error(e_t) || ty::type_is_bot(e_t) {
+                    fcx.write_ty(id, e_t);
+                    some_err = true;
+                  }
+              };
+              start.as_ref().map(|e| check_slice_idx(&**e));
+              end.as_ref().map(|e| check_slice_idx(&**e));
+          }
+
+          if !some_err {
+              let base_t = structurally_resolved_type(fcx,
+                                                      expr.span,
+                                                      raw_base_t);
+              let method_call = MethodCall::expr(expr.id);
+              match try_overloaded_slice(fcx,
+                                         Some(method_call),
+                                         expr,
+                                         &**base,
+                                         base_t,
+                                         start,
+                                         end,
+                                         mutbl) {
+                  Some(mt) => fcx.write_ty(id, mt.ty),
+                  None => {
+                        fcx.type_error_message(expr.span,
+                           |actual| {
+                                format!("cannot take a {}slice of a value with type `{}`",
+                                        if mutbl == &ast::MutMutable {
+                                            "mutable "
+                                        } else {
+                                            ""
+                                        },
+                                        actual)
+                           },
+                           base_t,
+                           None);
+                        fcx.write_ty(id, ty::mk_err())
+                  }
+              }
+          }
+       }
     }
 
     debug!("type of expr({}) {} is...", expr.id,
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index 415141c0b94..f98a2dac084 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -245,6 +245,7 @@ mod svh_visitor {
         SawExprAssign,
         SawExprAssignOp(ast::BinOp),
         SawExprIndex,
+        SawExprSlice,
         SawExprPath,
         SawExprAddrOf(ast::Mutability),
         SawExprRet,
@@ -279,6 +280,7 @@ mod svh_visitor {
             ExprField(_, id, _)      => SawExprField(content(id.node)),
             ExprTupField(_, id, _)   => SawExprTupField(id.node),
             ExprIndex(..)            => SawExprIndex,
+            ExprSlice(..)            => SawExprSlice,
             ExprPath(..)             => SawExprPath,
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
             ExprBreak(id)            => SawExprBreak(id.map(content)),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index eac158e664c..e2e40bc38f0 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -531,6 +531,7 @@ pub enum Expr_ {
     ExprField(P<Expr>, SpannedIdent, Vec<P<Ty>>),
     ExprTupField(P<Expr>, Spanned<uint>, Vec<P<Ty>>),
     ExprIndex(P<Expr>, P<Expr>),
+    ExprSlice(P<Expr>, Option<P<Expr>>, Option<P<Expr>>, Mutability),
 
     /// Variable reference, possibly containing `::` and/or
     /// type parameters, e.g. foo::bar::<baz>
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 3beba5bcda4..c71910779c2 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1242,6 +1242,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
             ExprIndex(el, er) => {
                 ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
             }
+            ExprSlice(e, e1, e2, m) => {
+                ExprSlice(folder.fold_expr(e),
+                          e1.map(|x| folder.fold_expr(x)),
+                          e2.map(|x| folder.fold_expr(x)),
+                          m)
+            }
             ExprPath(pth) => ExprPath(folder.fold_path(pth)),
             ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
             ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ff4fd41fbd7..1021a09177c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -23,7 +23,7 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
 use ast::{ExprBreak, ExprCall, ExprCast};
-use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIndex};
+use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIndex, ExprSlice};
 use ast::{ExprLit, ExprLoop, ExprMac};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
@@ -1986,6 +1986,14 @@ impl<'a> Parser<'a> {
         ExprIndex(expr, idx)
     }
 
+    pub fn mk_slice(&mut self, expr: P<Expr>,
+                    start: Option<P<Expr>>,
+                    end: Option<P<Expr>>,
+                    mutbl: Mutability)
+                    -> ast::Expr_ {
+        ExprSlice(expr, start, end, mutbl)
+    }
+
     pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent,
                     tys: Vec<P<Ty>>) -> ast::Expr_ {
         ExprField(expr, ident, tys)
@@ -2400,13 +2408,87 @@ impl<'a> Parser<'a> {
               }
 
               // expr[...]
+              // Could be either an index expression or a slicing expression.
+              // Any slicing non-terminal can have a mutable version with `mut`
+              // after the opening square bracket.
               token::LBRACKET => {
                 self.bump();
-                let ix = self.parse_expr();
-                hi = self.span.hi;
-                self.commit_expr_expecting(&*ix, token::RBRACKET);
-                let index = self.mk_index(e, ix);
-                e = self.mk_expr(lo, hi, index)
+                let mutbl = if self.eat_keyword(keywords::Mut) {
+                    MutMutable
+                } else {
+                    MutImmutable
+                };
+                match self.token {
+                    // e[]
+                    token::RBRACKET => {
+                        self.bump();
+                        hi = self.span.hi;
+                        let slice = self.mk_slice(e, None, None, mutbl);
+                        e = self.mk_expr(lo, hi, slice)
+                    }
+                    // e[..e]
+                    token::DOTDOT => {
+                        self.bump();
+                        match self.token {
+                            // e[..]
+                            token::RBRACKET => {
+                                self.bump();
+                                hi = self.span.hi;
+                                let slice = self.mk_slice(e, None, None, mutbl);
+                                e = self.mk_expr(lo, hi, slice);
+
+                                self.span_err(e.span, "incorrect slicing expression: `[..]`");
+                                self.span_note(e.span,
+                                    "use `expr[]` to construct a slice of the whole of expr");
+                            }
+                            // e[..e]
+                            _ => {
+                                hi = self.span.hi;
+                                let e2 = self.parse_expr();
+                                self.commit_expr_expecting(&*e2, token::RBRACKET);
+                                let slice = self.mk_slice(e, None, Some(e2), mutbl);
+                                e = self.mk_expr(lo, hi, slice)
+                            }
+                        }
+                    }
+                    // e[e] | e[e..] | e[e..e]
+                    _ => {
+                        let ix = self.parse_expr();
+                        match self.token {
+                            // e[e..] | e[e..e]
+                            token::DOTDOT => {
+                                self.bump();
+                                let e2 = match self.token {
+                                    // e[e..]
+                                    token::RBRACKET => {
+                                        self.bump();
+                                        None
+                                    }
+                                    // e[e..e]
+                                    _ => {
+                                        let e2 = self.parse_expr();
+                                        self.commit_expr_expecting(&*e2, token::RBRACKET);
+                                        Some(e2)
+                                    }
+                                };
+                                hi = self.span.hi;
+                                let slice = self.mk_slice(e, Some(ix), e2, mutbl);
+                                e = self.mk_expr(lo, hi, slice)
+                            }
+                            // e[e]
+                            _ => {
+                                if mutbl == ast::MutMutable {
+                                    self.span_err(e.span,
+                                                  "`mut` keyword is invalid in index expressions");
+                                }
+                                hi = self.span.hi;
+                                self.commit_expr_expecting(&*ix, token::RBRACKET);
+                                let index = self.mk_index(e, ix);
+                                e = self.mk_expr(lo, hi, index)
+                            }
+                        }
+                    }
+                }
               }
 
               _ => return e
@@ -3153,7 +3235,8 @@ impl<'a> Parser<'a> {
             // These expressions are limited to literals (possibly
             // preceded by unary-minus) or identifiers.
             let val = self.parse_literal_maybe_minus();
-            if self.token == token::DOTDOT &&
+            // FIXME(#17295) remove the DOTDOT option.
+            if (self.token == token::DOTDOTDOT || self.token == token::DOTDOT) &&
                     self.look_ahead(1, |t| {
                         *t != token::COMMA && *t != token::RBRACKET
                     }) {
@@ -3198,12 +3281,16 @@ impl<'a> Parser<'a> {
                 }
             });
 
-            if self.look_ahead(1, |t| *t == token::DOTDOT) &&
+            // FIXME(#17295) remove the DOTDOT option.
+            if self.look_ahead(1, |t| *t == token::DOTDOTDOT || *t == token::DOTDOT) &&
                     self.look_ahead(2, |t| {
                         *t != token::COMMA && *t != token::RBRACKET
                     }) {
                 let start = self.parse_expr_res(RestrictionNoBarOp);
-                self.eat(&token::DOTDOT);
+                // FIXME(#17295) remove the DOTDOT option (self.eat(&token::DOTDOTDOT)).
+                if self.token == token::DOTDOTDOT || self.token == token::DOTDOT {
+                    self.bump();
+                }
                 let end = self.parse_expr_res(RestrictionNoBarOp);
                 pat = PatRange(start, end);
             } else if is_plain_ident(&self.token) && !can_be_enum_or_struct {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 0ae5303641b..c6b9a3bceab 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1651,6 +1651,28 @@ impl<'a> State<'a> {
                 try!(self.print_expr(&**index));
                 try!(word(&mut self.s, "]"));
             }
+            ast::ExprSlice(ref e, ref start, ref end, ref mutbl) => {
+                try!(self.print_expr(&**e));
+                try!(word(&mut self.s, "["));
+                if mutbl == &ast::MutMutable {
+                    try!(word(&mut self.s, "mut"));
+                    if start.is_some() || end.is_some() {
+                        try!(space(&mut self.s));
+                    }
+                }
+                match start {
+                    &Some(ref e) => try!(self.print_expr(&**e)),
+                    _ => {}
+                }
+                if start.is_some() || end.is_some() {
+                    try!(word(&mut self.s, ".."));
+                }
+                match end {
+                    &Some(ref e) => try!(self.print_expr(&**e)),
+                    _ => {}
+                }
+                try!(word(&mut self.s, "]"));
+            }
             ast::ExprPath(ref path) => try!(self.print_path(path, true)),
             ast::ExprBreak(opt_ident) => {
                 try!(word(&mut self.s, "break"));
@@ -1944,7 +1966,7 @@ impl<'a> State<'a> {
             ast::PatRange(ref begin, ref end) => {
                 try!(self.print_expr(&**begin));
                 try!(space(&mut self.s));
-                try!(word(&mut self.s, ".."));
+                try!(word(&mut self.s, "..."));
                 try!(self.print_expr(&**end));
             }
             ast::PatVec(ref before, ref slice, ref after) => {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d425c60f4c9..32084856817 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -785,6 +785,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(&**main_expression);
             visitor.visit_expr(&**index_expression)
         }
+        ExprSlice(ref main_expression, ref start, ref end, _) => {
+            visitor.visit_expr(&**main_expression);
+            walk_expr_opt(visitor, start);
+            walk_expr_opt(visitor, end)
+        }
         ExprPath(ref path) => {
             visitor.visit_path(path, expression.id)
         }
diff --git a/src/test/compile-fail/slice-1.rs b/src/test/compile-fail/slice-1.rs
new file mode 100644
index 00000000000..622195a41c2
--- /dev/null
+++ b/src/test/compile-fail/slice-1.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test slicing expr[..] is an error and gives a helpful error message.
+
+struct Foo;
+
+fn main() {
+    let x = Foo;
+    x[..]; //~ ERROR incorrect slicing expression: `[..]`
+    //~^ NOTE use `expr[]` to construct a slice of the whole of expr
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/slice-2.rs b/src/test/compile-fail/slice-2.rs
new file mode 100644
index 00000000000..da00aa48ae0
--- /dev/null
+++ b/src/test/compile-fail/slice-2.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that slicing syntax gives errors if we have not implemented the trait.
+
+struct Foo;
+
+fn main() {
+    let x = Foo;
+    x[]; //~ ERROR cannot take a slice of a value with type `Foo`
+    x[Foo..]; //~ ERROR cannot take a slice of a value with type `Foo`
+    x[..Foo]; //~ ERROR cannot take a slice of a value with type `Foo`
+    x[Foo..Foo]; //~ ERROR cannot take a slice of a value with type `Foo`
+    x[mut]; //~ ERROR cannot take a mutable slice of a value with type `Foo`
+    x[mut Foo..]; //~ ERROR cannot take a mutable slice of a value with type `Foo`
+    x[mut ..Foo]; //~ ERROR cannot take a mutable slice of a value with type `Foo`
+    x[mut Foo..Foo]; //~ ERROR cannot take a mutable slice of a value with type `Foo`
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/slice-borrow.rs b/src/test/compile-fail/slice-borrow.rs
new file mode 100644
index 00000000000..3d12511134f
--- /dev/null
+++ b/src/test/compile-fail/slice-borrow.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test slicing expressions doesn't defeat the borrow checker.
+
+fn main() {
+    let y;
+    {
+        let x: &[int] = &[1, 2, 3, 4, 5]; //~ ERROR borrowed value does not live long enough
+        y = x[1..];
+    }
+}
diff --git a/src/test/compile-fail/slice-mut-2.rs b/src/test/compile-fail/slice-mut-2.rs
new file mode 100644
index 00000000000..1176b637cec
--- /dev/null
+++ b/src/test/compile-fail/slice-mut-2.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test mutability and slicing syntax.
+
+fn main() {
+    let x: &[int] = &[1, 2, 3, 4, 5];
+    // Can't mutably slice an immutable slice
+    let y = x[mut 2..4]; //~ ERROR cannot take a mutable slice of a value with type `&[int]`
+}
diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs
new file mode 100644
index 00000000000..8cd7c4ed0bb
--- /dev/null
+++ b/src/test/compile-fail/slice-mut.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test mutability and slicing syntax.
+
+fn main() {
+    let x: &[int] = &[1, 2, 3, 4, 5];
+    // Immutable slices are not mutable.
+    let y: &mut[_] = x[2..4]; //~ ERROR cannot borrow immutable dereference of `&`-pointer as mutabl
+
+    let x: &mut [int] = &mut [1, 2, 3, 4, 5];
+    // Can't borrow mutably twice
+    let y = x[mut 1..2];
+    let y = x[mut 4..5]; //~ERROR cannot borrow
+}
diff --git a/src/test/run-pass/match-range-static.rs b/src/test/run-pass/match-range-static.rs
index 039b3f9a26c..08875699245 100644
--- a/src/test/run-pass/match-range-static.rs
+++ b/src/test/run-pass/match-range-static.rs
@@ -13,7 +13,7 @@ static e: int = 42;
 
 pub fn main() {
     match 7 {
-        s..e => (),
+        s...e => (),
         _ => (),
     }
 }
diff --git a/src/test/run-pass/slice-2.rs b/src/test/run-pass/slice-2.rs
new file mode 100644
index 00000000000..3c0933a055c
--- /dev/null
+++ b/src/test/run-pass/slice-2.rs
@@ -0,0 +1,69 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test slicing expressions on slices and Vecs.
+
+fn main() {
+    let x: &[int] = &[1, 2, 3, 4, 5];
+    let cmp: &[int] = &[1, 2, 3, 4, 5];
+    assert!(x[] == cmp)
+    let cmp: &[int] = &[3, 4, 5];
+    assert!(x[2..] == cmp)
+    let cmp: &[int] = &[1, 2, 3];
+    assert!(x[..3] == cmp)
+    let cmp: &[int] = &[2, 3, 4];
+    assert!(x[1..4] == cmp)
+
+    let x: Vec<int> = vec![1, 2, 3, 4, 5];
+    let cmp: &[int] = &[1, 2, 3, 4, 5];
+    assert!(x[] == cmp)
+    let cmp: &[int] = &[3, 4, 5];
+    assert!(x[2..] == cmp)
+    let cmp: &[int] = &[1, 2, 3];
+    assert!(x[..3] == cmp)
+    let cmp: &[int] = &[2, 3, 4];
+    assert!(x[1..4] == cmp)
+
+    let x: &mut [int] = &mut [1, 2, 3, 4, 5];
+    {
+        let cmp: &mut [int] = &mut [1, 2, 3, 4, 5];
+        assert!(x[mut] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [3, 4, 5];
+        assert!(x[mut 2..] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [1, 2, 3];
+        assert!(x[mut ..3] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [2, 3, 4];
+        assert!(x[mut 1..4] == cmp)
+    }
+
+    let mut x: Vec<int> = vec![1, 2, 3, 4, 5];
+    {
+        let cmp: &mut [int] = &mut [1, 2, 3, 4, 5];
+        assert!(x[mut] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [3, 4, 5];
+        assert!(x[mut 2..] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [1, 2, 3];
+        assert!(x[mut ..3] == cmp)
+    }
+    {
+        let cmp: &mut [int] = &mut [2, 3, 4];
+        assert!(x[mut 1..4] == cmp)
+    }
+}
diff --git a/src/test/run-pass/slice.rs b/src/test/run-pass/slice.rs
new file mode 100644
index 00000000000..1aa40f0d492
--- /dev/null
+++ b/src/test/run-pass/slice.rs
@@ -0,0 +1,70 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test slicing sugar.
+
+extern crate core;
+use core::ops::{Slice,SliceMut};
+
+static mut COUNT: uint = 0;
+
+struct Foo;
+
+impl Slice<Foo, Foo> for Foo {
+    fn as_slice_<'a>(&'a self) -> &'a Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_from_<'a>(&'a self, _from: &Foo) -> &'a Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_to_<'a>(&'a self, _to: &Foo) -> &'a Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_<'a>(&'a self, _from: &Foo, _to: &Foo) -> &'a Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+}
+
+impl SliceMut<Foo, Foo> for Foo {
+    fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_from_mut_<'a>(&'a mut self, _from: &Foo) -> &'a mut Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_to_mut_<'a>(&'a mut self, _to: &Foo) -> &'a mut Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+    fn slice_mut_<'a>(&'a mut self, _from: &Foo, _to: &Foo) -> &'a mut Foo {
+        unsafe { COUNT += 1; }
+        self
+    }
+}
+fn main() {
+    let mut x = Foo;
+    x[];
+    x[Foo..];
+    x[..Foo];
+    x[Foo..Foo];
+    x[mut];
+    x[mut Foo..];
+    x[mut ..Foo];
+    x[mut Foo..Foo];
+    unsafe {
+        assert!(COUNT == 8);
+    }
+}
\ No newline at end of file