rollup merge of #17318 : nick29581/slice

This commit is contained in:
Alex Crichton 2014-09-19 10:00:24 -07:00
commit 81ee3586b5
29 changed files with 975 additions and 105 deletions

View File

@ -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!();

View File

@ -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,11 +669,110 @@ 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

View File

@ -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"]

View File

@ -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())
}

View File

@ -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) {

View File

@ -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;

View File

@ -501,7 +501,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(..) |
@ -1174,6 +1174,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) |
@ -1457,7 +1463,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(..) => {

View File

@ -494,7 +494,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(..) |

View File

@ -858,10 +858,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.
@ -1045,17 +1045,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) => {

View File

@ -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() {

View File

@ -589,6 +589,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);
@ -724,7 +752,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) {
@ -1043,20 +1071,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:
@ -1740,7 +1768,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;
@ -2063,7 +2091,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 => {

View File

@ -3646,6 +3646,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,
@ -3698,7 +3701,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
}

View File

@ -109,7 +109,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;
@ -123,7 +123,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;
@ -2187,12 +2186,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) {
@ -2275,18 +2274,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,
}
}
@ -2332,32 +2438,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
@ -2441,14 +2531,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,
@ -2482,14 +2572,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
@ -2626,7 +2716,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);
}
}
}
@ -2635,12 +2725,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,
@ -2876,10 +2966,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);
@ -2989,11 +3079,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);
@ -3084,12 +3175,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) => {
@ -3101,7 +3188,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
op_ex.span,
method_ty,
op_ex,
args,
args.as_slice(),
DoDerefArgs,
DontTupleArguments)
}
@ -3114,7 +3201,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
op_ex.span,
expected_ty,
op_ex,
args,
args.as_slice(),
DoDerefArgs,
DontTupleArguments);
ty::mk_err()
@ -4135,12 +4222,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 {
@ -4426,6 +4514,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,

View File

@ -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)),

View File

@ -538,6 +538,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>

View File

@ -1252,6 +1252,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))),

View File

@ -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};
@ -1987,6 +1987,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)
@ -2401,13 +2409,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
@ -3154,7 +3236,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
}) {
@ -3199,12 +3282,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 {

View File

@ -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) => {

View File

@ -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)
}

View File

@ -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
}

View File

@ -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`
}

View File

@ -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..];
}
}

View File

@ -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]`
}

View File

@ -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
}

View File

@ -13,7 +13,7 @@ static e: int = 42;
pub fn main() {
match 7 {
s..e => (),
s...e => (),
_ => (),
}
}

View File

@ -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)
}
}

View File

@ -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 <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 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); }
}

View File

@ -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 <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 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); }
}

View File

@ -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);
}
}