From 31a7e38759cc50b5135e73232dc9fa98e5154710 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 15 Sep 2014 20:48:58 +1200 Subject: [PATCH 1/2] Implement slicing syntax. `expr[]`, `expr[expr..]`, `expr[..expr]`,`expr[expr..expr]` Uses the Slice and SliceMut traits. Allows ... as well as .. in range patterns. --- src/libcollections/vec.rs | 80 +++++++ src/libcore/ops.rs | 105 ++++++++- src/libcore/slice.rs | 58 +++++ src/librustc/middle/cfg/construct.rs | 7 + src/librustc/middle/expr_use_visitor.rs | 21 +- src/librustc/middle/lang_items.rs | 2 + src/librustc/middle/liveness.rs | 10 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/trans/callee.rs | 24 +- src/librustc/middle/trans/debuginfo.rs | 6 + src/librustc/middle/trans/expr.rs | 40 +++- src/librustc/middle/ty.rs | 6 +- src/librustc/middle/typeck/check/mod.rs | 267 +++++++++++++++++----- src/librustc_back/svh.rs | 2 + src/libsyntax/ast.rs | 1 + src/libsyntax/fold.rs | 6 + src/libsyntax/parse/parser.rs | 105 ++++++++- src/libsyntax/print/pprust.rs | 24 +- src/libsyntax/visit.rs | 5 + src/test/compile-fail/slice-1.rs | 19 ++ src/test/compile-fail/slice-2.rs | 25 ++ src/test/compile-fail/slice-borrow.rs | 19 ++ src/test/compile-fail/slice-mut-2.rs | 17 ++ src/test/compile-fail/slice-mut.rs | 22 ++ src/test/run-pass/match-range-static.rs | 2 +- src/test/run-pass/slice-2.rs | 69 ++++++ src/test/run-pass/slice.rs | 70 ++++++ 27 files changed, 909 insertions(+), 105 deletions(-) create mode 100644 src/test/compile-fail/slice-1.rs create mode 100644 src/test/compile-fail/slice-2.rs create mode 100644 src/test/compile-fail/slice-borrow.rs create mode 100644 src/test/compile-fail/slice-mut-2.rs create mode 100644 src/test/compile-fail/slice-mut.rs create mode 100644 src/test/run-pass/slice-2.rs create mode 100644 src/test/run-pass/slice.rs 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 Index for Vec { } }*/ +impl ops::Slice for Vec { + #[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 ops::SliceMut for Vec { + #[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 FromIterator for Vec { #[inline] fn from_iter>(mut iterator: I) -> Vec { @@ -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 = vec![1, 2, 3, 4, 5]; + x[-1..]; + } + + #[test] + #[should_fail] + fn test_slice_out_of_bounds_2() { + let x: Vec = vec![1, 2, 3, 4, 5]; + x[..6]; + } + + #[test] + #[should_fail] + fn test_slice_out_of_bounds_3() { + let x: Vec = vec![1, 2, 3, 4, 5]; + x[-1..4]; + } + + #[test] + #[should_fail] + fn test_slice_out_of_bounds_4() { + let x: Vec = vec![1, 2, 3, 4, 5]; + x[1..6]; + } + + #[test] + #[should_fail] + fn test_slice_out_of_bounds_5() { + let x: Vec = vec![1, 2, 3, 4, 5]; + x[3..2]; + } + */ + #[test] fn test_swap_remove_empty() { let mut vec: Vec = 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 { +pub trait Index { /// The method for the indexing (`Foo[Bar]`) operation fn index<'a>(&'a self, index: &Index) -> &'a Result; } @@ -651,7 +651,7 @@ pub trait Index { * # 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,11 +669,110 @@ pub trait Index { * ``` */ #[lang="index_mut"] -pub trait IndexMut { +pub trait IndexMut { /// 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 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 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 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 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 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 ops::Slice 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 ops::SliceMut 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::.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, Option<(Datum, ast::NodeId)>), + // the right-hand-side arguments (if any). + ArgOverloadedOp(Datum, Vec<(Datum, 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` and `Gc` 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, - rhs: Option<(Datum, ast::NodeId)>, + rhs: Vec<(Datum, ast::NodeId)>, dest: Option) -> 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(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]) - -> bool { +fn try_overloaded_call<'a>(fcx: &FnCtxt, + call_expression: &ast::Expr, + callee: &ast::Expr, + callee_type: ty::t, + args: &[&'a P]) + -> 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) -> ty::t { + match method { + &Some(ref method) => method.ty, + &None => ty::mk_err() + } +} + +fn make_return_type(fcx: &FnCtxt, + method_call: Option, + method: Option) + -> Option { 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, + expr: &ast::Expr, + base_expr: &ast::Expr, + base_ty: ty::t, + start_expr: &Option>, + end_expr: &Option>, + mutbl: &ast::Mutability) + -> Option { + 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], - 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], + 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], - 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], + 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]) { + fn check_call<'a>(fcx: &FnCtxt, + call_expr: &ast::Expr, + f: &ast::Expr, + args: &[&'a P]) { // 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, SpannedIdent, Vec>), ExprTupField(P, Spanned, Vec>), ExprIndex(P, P), + ExprSlice(P, Option>, Option>, Mutability), /// Variable reference, possibly containing `::` and/or /// type parameters, e.g. foo::bar:: 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(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, + start: Option>, + end: Option>, + mutbl: Mutability) + -> ast::Expr_ { + ExprSlice(expr, start, end, mutbl) + } + pub fn mk_field(&mut self, expr: P, ident: ast::SpannedIdent, tys: Vec>) -> 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 = 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 = 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 or the MIT license +// , 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 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 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 From cf9c586fccb1063ea6f75609c702df909d4ac3f1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 18 Sep 2014 09:33:31 +1200 Subject: [PATCH 2/2] reviewer changes --- src/test/compile-fail/slice-1.rs | 2 +- src/test/compile-fail/slice-2.rs | 2 +- src/test/run-pass/slice-fail-1.rs | 31 +++++++++++++++++++++++++++ src/test/run-pass/slice-fail-2.rs | 35 +++++++++++++++++++++++++++++++ src/test/run-pass/slice.rs | 2 +- 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/slice-fail-1.rs create mode 100644 src/test/run-pass/slice-fail-2.rs diff --git a/src/test/compile-fail/slice-1.rs b/src/test/compile-fail/slice-1.rs index 622195a41c2..d0339745c9e 100644 --- a/src/test/compile-fail/slice-1.rs +++ b/src/test/compile-fail/slice-1.rs @@ -16,4 +16,4 @@ 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 index da00aa48ae0..fbfc438321c 100644 --- a/src/test/compile-fail/slice-2.rs +++ b/src/test/compile-fail/slice-2.rs @@ -22,4 +22,4 @@ fn main() { 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/run-pass/slice-fail-1.rs b/src/test/run-pass/slice-fail-1.rs new file mode 100644 index 00000000000..f6972023a72 --- /dev/null +++ b/src/test/run-pass/slice-fail-1.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that is a slicing expr[..] fails, the correct cleanups happen. + +use std::task; + +struct Foo; + +static mut DTOR_COUNT: int = 0; + +impl Drop for Foo { + fn drop(&mut self) { unsafe { DTOR_COUNT += 1; } } +} + +fn foo() { + let x: &[_] = &[Foo, Foo]; + x[3..4]; +} + +fn main() { + let _ = task::try(proc() foo()); + unsafe { assert!(DTOR_COUNT == 2); } +} diff --git a/src/test/run-pass/slice-fail-2.rs b/src/test/run-pass/slice-fail-2.rs new file mode 100644 index 00000000000..cbe65fcd83d --- /dev/null +++ b/src/test/run-pass/slice-fail-2.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that is a slicing expr[..] fails, the correct cleanups happen. + +use std::task; + +struct Foo; + +static mut DTOR_COUNT: int = 0; + +impl Drop for Foo { + fn drop(&mut self) { unsafe { DTOR_COUNT += 1; } } +} + +fn bar() -> uint { + fail!(); +} + +fn foo() { + let x: &[_] = &[Foo, Foo]; + x[3..bar()]; +} + +fn main() { + let _ = task::try(proc() foo()); + unsafe { assert!(DTOR_COUNT == 2); } +} diff --git a/src/test/run-pass/slice.rs b/src/test/run-pass/slice.rs index 1aa40f0d492..39feb075add 100644 --- a/src/test/run-pass/slice.rs +++ b/src/test/run-pass/slice.rs @@ -67,4 +67,4 @@ fn main() { unsafe { assert!(COUNT == 8); } -} \ No newline at end of file +}